urcu/uatomic.h
tests/api.h
-tests/urcutorture
-tests/urcutorture-yield
-tests/urcu-asm.S
-tests/test_rwlock_timing
-tests/test_urcu
-tests/test_urcu_dynamic_link
-tests/test_urcu_timing
-tests/test_urcu_yield
-tests/test_looplen
-tests/test_mutex
-tests/test_perthreadlock
-tests/test_perthreadlock_timing
-tests/test_qsbr
-tests/test_qsbr_dynamic_link
-tests/test_qsbr_gc
-tests/test_qsbr_lgc
-tests/test_qsbr_timing
-tests/test_rwlock
-tests/test_uatomic
-tests/test_urcu_gc
-tests/test_urcu_gc_mb
-tests/test_urcu_lgc
-tests/test_urcu_lgc_mb
-tests/test_urcu_mb
-tests/test_urcu_mb_defer
-tests/test_urcu_assign
-tests/test_urcu_assign_dynamic_link
-tests/test_urcu_bp
-tests/test_urcu_bp_dynamic_link
-tests/rcutorture_qsbr
-tests/rcutorture_urcu
-tests/rcutorture_urcu_bp
-tests/rcutorture_urcu_mb
-tests/rcutorture_urcu_qsbr
-tests/rcutorture_urcu_signal
-tests/test_cycles_per_loop
-tests/test_urcu_defer
-tests/test_urcu_hash
-tests/test_urcu_lfq
-tests/test_urcu_lfq_dynlink
-tests/test_urcu_lfs
-tests/test_urcu_lfs_dynlink
-tests/test_urcu_mb_gc
-tests/test_urcu_mb_lgc
-tests/test_urcu_qsbr
-tests/test_urcu_qsbr_dynamic_link
-tests/test_urcu_qsbr_gc
-tests/test_urcu_qsbr_lgc
-tests/test_urcu_qsbr_timing
-tests/test_urcu_signal
-tests/test_urcu_signal_dynamic_link
-tests/test_urcu_signal_gc
-tests/test_urcu_signal_lgc
-tests/test_urcu_signal_timing
-tests/test_urcu_signal_yield
-tests/test_urcu_wfq
-tests/test_urcu_wfq_dynlink
-tests/test_urcu_wfs
-tests/test_urcu_wfs_dynlink
-tests/test_urcu_fork
-tests/test_urcu_ja
-tests/test_urcu_ja_range
-tests/test_urcu_lfs_rcu
-tests/test_urcu_lfs_rcu_dynlink
-tests/test_urcu_multiflavor
-tests/test_urcu_multiflavor_dynlink
-tests/test_urcu_wfcq
-tests/test_urcu_wfcq_dynlink
-tests/*.log
+
+tests/unit/urcu-asm.S
+tests/unit/test_uatomic
+tests/unit/test_urcu_multiflavor
+tests/unit/test_urcu_multiflavor_dynlink
+
+tests/regression/rcutorture_qsbr
+tests/regression/rcutorture_urcu
+tests/regression/rcutorture_urcu_bp
+tests/regression/rcutorture_urcu_mb
+tests/regression/rcutorture_urcu_qsbr
+tests/regression/rcutorture_urcu_signal
+tests/regression/test_urcu_fork
+
+tests/benchmark/test_rwlock_timing
+tests/benchmark/test_urcu
+tests/benchmark/test_urcu_dynamic_link
+tests/benchmark/test_urcu_timing
+tests/benchmark/test_urcu_yield
+tests/benchmark/test_looplen
+tests/benchmark/test_mutex
+tests/benchmark/test_perthreadlock
+tests/benchmark/test_perthreadlock_timing
+tests/benchmark/test_qsbr
+tests/benchmark/test_qsbr_dynamic_link
+tests/benchmark/test_qsbr_gc
+tests/benchmark/test_qsbr_lgc
+tests/benchmark/test_qsbr_timing
+tests/benchmark/test_rwlock
+tests/benchmark/test_urcu_gc
+tests/benchmark/test_urcu_gc_mb
+tests/benchmark/test_urcu_lgc
+tests/benchmark/test_urcu_lgc_mb
+tests/benchmark/test_urcu_mb
+tests/benchmark/test_urcu_mb_defer
+tests/benchmark/test_urcu_assign
+tests/benchmark/test_urcu_assign_dynamic_link
+tests/benchmark/test_urcu_bp
+tests/benchmark/test_urcu_bp_dynamic_link
+tests/benchmark/test_cycles_per_loop
+tests/benchmark/test_urcu_defer
+tests/benchmark/test_urcu_hash
+tests/benchmark/test_urcu_lfq
+tests/benchmark/test_urcu_lfq_dynlink
+tests/benchmark/test_urcu_lfs
+tests/benchmark/test_urcu_lfs_dynlink
+tests/benchmark/test_urcu_mb_gc
+tests/benchmark/test_urcu_mb_lgc
+tests/benchmark/test_urcu_qsbr
+tests/benchmark/test_urcu_qsbr_dynamic_link
+tests/benchmark/test_urcu_qsbr_gc
+tests/benchmark/test_urcu_qsbr_lgc
+tests/benchmark/test_urcu_qsbr_timing
+tests/benchmark/test_urcu_signal
+tests/benchmark/test_urcu_signal_dynamic_link
+tests/benchmark/test_urcu_signal_gc
+tests/benchmark/test_urcu_signal_lgc
+tests/benchmark/test_urcu_signal_timing
+tests/benchmark/test_urcu_signal_yield
+tests/benchmark/test_urcu_wfq
+tests/benchmark/test_urcu_wfq_dynlink
+tests/benchmark/test_urcu_wfs
+tests/benchmark/test_urcu_wfs_dynlink
+tests/benchmark/test_urcu_ja
+tests/benchmark/test_urcu_ja_range
+tests/benchmark/test_urcu_lfs_rcu
+tests/benchmark/test_urcu_lfs_rcu_dynlink
+tests/benchmark/test_urcu_wfcq
+tests/benchmark/test_urcu_wfcq_dynlink
+
+tests/benchmark/*.log
*.so
doc/examples/urcu-flavors/qsbr
gpl-2.0.txt lgpl-2.1.txt lgpl-relicensing.txt \
LICENSE compat_arch_x86.c \
urcu-call-rcu-impl.h urcu-defer-impl.h \
- rculfhash-internal.h \
- $(top_srcdir)/tests/*.sh
+ rculfhash-internal.h
if COMPAT_ARCH
COMPAT=compat_arch_@ARCHTYPE@.c
dist_doc_DATA = README ChangeLog
dist_noinst_DATA = CodingStyle
+
+.PHONY: bench regtest
+bench:
+ cd tests && $(MAKE) $(AM_MAKEFLAGS) bench
+regtest:
+ cd tests && $(MAKE) $(AM_MAKEFLAGS) regtest
doc/Makefile
doc/examples/Makefile
tests/Makefile
+ tests/common/Makefile
+ tests/unit/Makefile
+ tests/benchmark/Makefile
+ tests/regression/Makefile
liburcu.pc
liburcu-bp.pc
liburcu-cds.pc
-AM_LDFLAGS=-lpthread
-AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -g
+SUBDIRS = common unit benchmark regression
-noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \
- test_urcu_signal test_urcu_signal_dynamic_link test_urcu_signal_timing \
- test_rwlock_timing test_rwlock test_perthreadlock_timing \
- test_perthreadlock test_urcu_yield test_urcu_signal_yield test_urcu_mb \
- test_urcu_qsbr_timing test_urcu_qsbr rcutorture_urcu rcutorture_urcu_signal \
- rcutorture_urcu_mb rcutorture_urcu_bp rcutorture_urcu_qsbr \
- test_mutex test_looplen test_urcu_gc test_urcu_signal_gc \
- test_urcu_lgc \
- test_urcu_mb_gc test_urcu_qsbr_gc test_urcu_qsbr_lgc test_urcu_signal_lgc \
- test_urcu_mb_lgc test_urcu_qsbr_dynamic_link test_urcu_defer \
- test_uatomic test_urcu_assign test_urcu_assign_dynamic_link \
- test_urcu_bp test_urcu_bp_dynamic_link test_cycles_per_loop \
- test_urcu_lfq test_urcu_wfq test_urcu_lfs test_urcu_wfs \
- test_urcu_lfs_rcu \
- test_urcu_wfcq \
- test_urcu_wfq_dynlink test_urcu_wfs_dynlink \
- test_urcu_wfcq_dynlink \
- test_urcu_lfq_dynlink test_urcu_lfs_dynlink test_urcu_hash \
- test_urcu_lfs_rcu_dynlink \
- test_urcu_multiflavor test_urcu_multiflavor_dynlink \
- test_urcu_fork
-noinst_HEADERS = rcutorture.h test_urcu_multiflavor.h cpuset.h thread-id.h
+.PHONY: bench regtest
-if COMPAT_ARCH
-COMPAT=$(top_srcdir)/compat_arch_@ARCHTYPE@.c
-else
-COMPAT=
-endif
-
-if COMPAT_FUTEX
-COMPAT+=$(top_srcdir)/compat_futex.c
-endif
-
-URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-# URCU_MB uses urcu.c but -DRCU_MB must be defined
-URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-# URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined
-URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
-
-URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
-URCU_LIB=$(top_builddir)/liburcu.la
-URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
-URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
-URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
-URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
-URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
-
-EXTRA_DIST = $(top_srcdir)/tests/api.h runall.sh runhash.sh
-
-test_urcu_SOURCES = test_urcu.c $(URCU)
-
-test_urcu_dynamic_link_SOURCES = test_urcu.c $(URCU)
-test_urcu_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-
-test_urcu_timing_SOURCES = test_urcu_timing.c $(URCU)
-
-test_urcu_yield_SOURCES = test_urcu.c $(URCU)
-test_urcu_yield_CFLAGS = -DDEBUG_YIELD $(AM_CFLAGS)
-
-
-test_urcu_qsbr_SOURCES = test_urcu_qsbr.c $(URCU_QSBR)
-
-test_urcu_qsbr_timing_SOURCES = test_urcu_qsbr_timing.c $(URCU_QSBR)
-
-
-test_urcu_mb_SOURCES = test_urcu.c $(URCU_MB)
-test_urcu_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS)
-
-
-test_urcu_signal_SOURCES = test_urcu.c $(URCU_SIGNAL)
-test_urcu_signal_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
-
-test_urcu_signal_dynamic_link_SOURCES = test_urcu.c $(URCU_SIGNAL)
-test_urcu_signal_dynamic_link_CFLAGS = -DRCU_SIGNAL -DDYNAMIC_LINK_TEST \
- $(AM_CFLAGS)
-
-test_urcu_signal_timing_SOURCES = test_urcu_timing.c $(URCU_SIGNAL)
-test_urcu_signal_timing_CFLAGS= -DRCU_SIGNAL $(AM_CFLAGS)
-
-test_urcu_signal_yield_SOURCES = test_urcu.c $(URCU_SIGNAL)
-test_urcu_signal_yield_CFLAGS = -DRCU_SIGNAL -DDEBUG_YIELD $(AM_CFLAGS)
-
-test_urcu_fork_SOURCES = test_urcu_fork.c $(URCU)
-
-test_rwlock_timing_SOURCES = test_rwlock_timing.c $(URCU_SIGNAL)
-
-test_rwlock_SOURCES = test_rwlock.c $(URCU_SIGNAL)
-
-test_perthreadlock_timing_SOURCES = test_perthreadlock_timing.c $(URCU_SIGNAL)
-
-test_perthreadlock_SOURCES = test_perthreadlock.c $(URCU_SIGNAL)
-
-
-rcutorture_urcu_SOURCES = urcutorture.c
-rcutorture_urcu_CFLAGS = -DRCU_MEMBARRIER $(AM_CFLAGS)
-rcutorture_urcu_LDADD = $(URCU)
-
-rcutorture_urcu_mb_SOURCES = urcutorture.c
-rcutorture_urcu_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS)
-rcutorture_urcu_mb_LDADD = $(URCU_MB_LIB)
-
-rcutorture_urcu_qsbr_SOURCES = urcutorture.c
-rcutorture_urcu_qsbr_CFLAGS = -DTORTURE_QSBR -DRCU_QSBR $(AM_CFLAGS)
-rcutorture_urcu_qsbr_LDADD = $(URCU_QSBR_LIB)
-
-rcutorture_urcu_signal_SOURCES = urcutorture.c
-rcutorture_urcu_signal_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
-rcutorture_urcu_signal_LDADD = $(URCU_SIGNAL_LIB)
-
-rcutorture_urcu_bp_SOURCES = urcutorture.c
-rcutorture_urcu_bp_CFLAGS = -DRCU_BP $(AM_CFLAGS)
-rcutorture_urcu_bp_LDADD = $(URCU_BP_LIB)
-
-test_mutex_SOURCES = test_mutex.c $(URCU)
-
-test_looplen_SOURCES = test_looplen.c
-
-test_urcu_gc_SOURCES = test_urcu_gc.c $(URCU)
-
-test_urcu_signal_gc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL)
-test_urcu_signal_gc_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
-
-test_urcu_mb_gc_SOURCES = test_urcu_gc.c $(URCU_MB)
-test_urcu_mb_gc_CFLAGS = -DRCU_MB $(AM_CFLAGS)
-
-test_urcu_qsbr_gc_SOURCES = test_urcu_qsbr_gc.c $(URCU_QSBR)
-
-test_urcu_qsbr_lgc_SOURCES = test_urcu_qsbr_gc.c $(URCU_QSBR)
-test_urcu_qsbr_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS)
-
-test_urcu_lgc_SOURCES = test_urcu_gc.c $(URCU)
-test_urcu_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS)
-
-test_urcu_signal_lgc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL)
-test_urcu_signal_lgc_CFLAGS = -DRCU_SIGNAL -DTEST_LOCAL_GC $(AM_CFLAGS)
-
-test_urcu_mb_lgc_SOURCES = test_urcu_gc.c $(URCU_MB)
-test_urcu_mb_lgc_CFLAGS = -DTEST_LOCAL_GC -DRCU_MB $(AM_CFLAGS)
-
-test_urcu_qsbr_dynamic_link_SOURCES = test_urcu_qsbr.c $(URCU_QSBR)
-test_urcu_qsbr_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-
-test_urcu_defer_SOURCES = test_urcu_defer.c $(URCU_DEFER)
-
-test_uatomic_SOURCES = test_uatomic.c $(COMPAT)
-
-test_cycles_per_loop_SOURCES = test_cycles_per_loop.c
-
-test_urcu_assign_SOURCES = test_urcu_assign.c $(URCU)
-
-test_urcu_assign_dynamic_link_SOURCES = test_urcu_assign.c $(URCU)
-test_urcu_assign_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-
-test_urcu_bp_SOURCES = test_urcu_bp.c $(URCU_BP)
-
-test_urcu_bp_dynamic_link_SOURCES = test_urcu_bp.c $(URCU_BP)
-test_urcu_bp_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-
-test_urcu_lfq_SOURCES = test_urcu_lfq.c $(URCU)
-test_urcu_lfq_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_lfq_dynlink_SOURCES = test_urcu_lfq.c $(URCU)
-test_urcu_lfq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_lfq_dynlink_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_wfq_SOURCES = test_urcu_wfq.c $(COMPAT)
-test_urcu_wfq_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_wfq_dynlink_SOURCES = test_urcu_wfq.c
-test_urcu_wfq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_wfq_dynlink_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_wfcq_SOURCES = test_urcu_wfcq.c $(COMPAT)
-test_urcu_wfcq_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_wfcq_dynlink_SOURCES = test_urcu_wfcq.c
-test_urcu_wfcq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_wfcq_dynlink_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_lfs_SOURCES = test_urcu_lfs.c $(URCU)
-test_urcu_lfs_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_lfs_rcu_SOURCES = test_urcu_lfs_rcu.c $(URCU)
-test_urcu_lfs_rcu_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_lfs_dynlink_SOURCES = test_urcu_lfs.c $(URCU)
-test_urcu_lfs_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_lfs_dynlink_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_lfs_rcu_dynlink_SOURCES = test_urcu_lfs_rcu.c $(URCU)
-test_urcu_lfs_rcu_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_lfs_rcu_dynlink_LDADD = $(URCU_CDS_LIB)
-
-test_urcu_wfs_SOURCES = test_urcu_wfs.c $(COMPAT)
-test_urcu_wfs_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_wfs_dynlink_SOURCES = test_urcu_wfs.c
-test_urcu_wfs_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_wfs_dynlink_LDADD = $(URCU_COMMON_LIB)
-
-test_urcu_hash_SOURCES = test_urcu_hash.c test_urcu_hash.h \
- test_urcu_hash_rw.c test_urcu_hash_unique.c $(COMPAT)
-test_urcu_hash_CFLAGS = -DRCU_QSBR $(AM_CFLAGS)
-test_urcu_hash_LDADD = $(URCU_QSBR_LIB) $(URCU_CDS_LIB)
-
-test_urcu_multiflavor_SOURCES = test_urcu_multiflavor.c \
- test_urcu_multiflavor-memb.c \
- test_urcu_multiflavor-mb.c \
- test_urcu_multiflavor-signal.c \
- test_urcu_multiflavor-qsbr.c \
- test_urcu_multiflavor-bp.c
-test_urcu_multiflavor_LDADD = $(URCU_LIB) $(URCU_MB_LIB) \
- $(URCU_SIGNAL_LIB) $(URCU_QSBR_LIB) $(URCU_BP_LIB)
-
-test_urcu_multiflavor_dynlink_SOURCES = test_urcu_multiflavor.c \
- test_urcu_multiflavor-memb.c \
- test_urcu_multiflavor-mb.c \
- test_urcu_multiflavor-signal.c \
- test_urcu_multiflavor-qsbr.c \
- test_urcu_multiflavor-bp.c
-test_urcu_multiflavor_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
-test_urcu_multiflavor_dynlink_LDADD = $(URCU_LIB) $(URCU_MB_LIB) \
- $(URCU_SIGNAL_LIB) $(URCU_QSBR_LIB) $(URCU_BP_LIB)
-
-urcutorture.c: api.h
-
-check-am:
- ./test_uatomic
- ./runall.sh
+bench:
+ cd benchmark && $(MAKE) $(AM_MAKEFLAGS) bench
+regtest:
+ cd regression && $(MAKE) $(AM_MAKEFLAGS) regtest
+++ /dev/null
-#ifndef _INCLUDE_API_H
-#define _INCLUDE_API_H
-
-#define _GNU_SOURCE
-#include "../config.h"
-
-/*
- * common.h: Common Linux kernel-isms.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; but version 2 of the License only due
- * to code included from the Linux kernel.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (c) 2006 Paul E. McKenney, IBM.
- *
- * Much code taken from the Linux kernel. For such code, the option
- * to redistribute under later versions of GPL might not be available.
- */
-
-#include <urcu/compiler.h>
-#include <urcu/arch.h>
-#include "cpuset.h"
-
-/*
- * Machine parameters.
- */
-
-#define ____cacheline_internodealigned_in_smp \
- __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
-
-/*
- * api_pthreads.h: API mapping to pthreads environment.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version. However, please note that much
- * of the code in this file derives from the Linux kernel, and that such
- * code may not be available except under GPLv2.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (c) 2006 Paul E. McKenney, IBM.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <pthread.h>
-#include <sys/param.h>
-/* #include "atomic.h" */
-
-/*
- * Exclusive locking primitives.
- */
-
-typedef pthread_mutex_t spinlock_t;
-
-#define DEFINE_SPINLOCK(lock) spinlock_t lock = PTHREAD_MUTEX_INITIALIZER;
-#define __SPIN_LOCK_UNLOCKED(lockp) PTHREAD_MUTEX_INITIALIZER
-
-static void spin_lock_init(spinlock_t *sp)
-{
- if (pthread_mutex_init(sp, NULL) != 0) {
- perror("spin_lock_init:pthread_mutex_init");
- exit(-1);
- }
-}
-
-static void spin_lock(spinlock_t *sp)
-{
- if (pthread_mutex_lock(sp) != 0) {
- perror("spin_lock:pthread_mutex_lock");
- exit(-1);
- }
-}
-
-static void spin_unlock(spinlock_t *sp)
-{
- if (pthread_mutex_unlock(sp) != 0) {
- perror("spin_unlock:pthread_mutex_unlock");
- exit(-1);
- }
-}
-
-#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0)
-#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0)
-
-/*
- * Thread creation/destruction primitives.
- */
-
-typedef pthread_t thread_id_t;
-
-#define NR_THREADS 128
-
-#define __THREAD_ID_MAP_EMPTY ((thread_id_t) 0)
-#define __THREAD_ID_MAP_WAITING ((thread_id_t) 1)
-thread_id_t __thread_id_map[NR_THREADS];
-spinlock_t __thread_id_map_mutex;
-
-#define for_each_thread(t) \
- for (t = 0; t < NR_THREADS; t++)
-
-#define for_each_running_thread(t) \
- for (t = 0; t < NR_THREADS; t++) \
- if ((__thread_id_map[t] != __THREAD_ID_MAP_EMPTY) && \
- (__thread_id_map[t] != __THREAD_ID_MAP_WAITING))
-
-#define for_each_tid(t, tid) \
- for (t = 0; t < NR_THREADS; t++) \
- if ((((tid) = __thread_id_map[t]) != __THREAD_ID_MAP_EMPTY) && \
- ((tid) != __THREAD_ID_MAP_WAITING))
-
-pthread_key_t thread_id_key;
-
-static int __smp_thread_id(void)
-{
- int i;
- thread_id_t tid = pthread_self();
-
- for (i = 0; i < NR_THREADS; i++) {
- if (__thread_id_map[i] == tid) {
- long v = i + 1; /* must be non-NULL. */
-
- if (pthread_setspecific(thread_id_key, (void *)v) != 0) {
- perror("pthread_setspecific");
- exit(-1);
- }
- return i;
- }
- }
- spin_lock(&__thread_id_map_mutex);
- for (i = 0; i < NR_THREADS; i++) {
- if (__thread_id_map[i] == tid) {
- spin_unlock(&__thread_id_map_mutex);
- return i;
- }
- }
- spin_unlock(&__thread_id_map_mutex);
- fprintf(stderr, "smp_thread_id: Rogue thread, id: %lu(%#lx)\n",
- (unsigned long) tid, (unsigned long) tid);
- exit(-1);
-}
-
-static int smp_thread_id(void)
-{
- void *id;
-
- id = pthread_getspecific(thread_id_key);
- if (id == NULL)
- return __smp_thread_id();
- return (long)(id - 1);
-}
-
-static thread_id_t create_thread(void *(*func)(void *), void *arg)
-{
- thread_id_t tid;
- int i;
-
- spin_lock(&__thread_id_map_mutex);
- for (i = 0; i < NR_THREADS; i++) {
- if (__thread_id_map[i] == __THREAD_ID_MAP_EMPTY)
- break;
- }
- if (i >= NR_THREADS) {
- spin_unlock(&__thread_id_map_mutex);
- fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS);
- exit(-1);
- }
- __thread_id_map[i] = __THREAD_ID_MAP_WAITING;
- spin_unlock(&__thread_id_map_mutex);
- if (pthread_create(&tid, NULL, func, arg) != 0) {
- perror("create_thread:pthread_create");
- exit(-1);
- }
- __thread_id_map[i] = tid;
- return tid;
-}
-
-static void *wait_thread(thread_id_t tid)
-{
- int i;
- void *vp;
-
- for (i = 0; i < NR_THREADS; i++) {
- if (__thread_id_map[i] == tid)
- break;
- }
- if (i >= NR_THREADS){
- fprintf(stderr, "wait_thread: bad tid = %lu(%#lx)\n",
- (unsigned long)tid, (unsigned long)tid);
- exit(-1);
- }
- if (pthread_join(tid, &vp) != 0) {
- perror("wait_thread:pthread_join");
- exit(-1);
- }
- __thread_id_map[i] = __THREAD_ID_MAP_EMPTY;
- return vp;
-}
-
-static void wait_all_threads(void)
-{
- int i;
- thread_id_t tid;
-
- for (i = 1; i < NR_THREADS; i++) {
- tid = __thread_id_map[i];
- if (tid != __THREAD_ID_MAP_EMPTY &&
- tid != __THREAD_ID_MAP_WAITING)
- (void)wait_thread(tid);
- }
-}
-
-static void run_on(int cpu)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * timekeeping -- very crude -- should use MONOTONIC...
- */
-
-long long get_microseconds(void)
-{
- struct timeval tv;
-
- if (gettimeofday(&tv, NULL) != 0)
- abort();
- return ((long long)tv.tv_sec) * 1000000LL + (long long)tv.tv_usec;
-}
-
-/*
- * Per-thread variables.
- */
-
-#define DEFINE_PER_THREAD(type, name) \
- struct { \
- __typeof__(type) v \
- __attribute__((__aligned__(CAA_CACHE_LINE_SIZE))); \
- } __per_thread_##name[NR_THREADS];
-#define DECLARE_PER_THREAD(type, name) extern DEFINE_PER_THREAD(type, name)
-
-#define per_thread(name, thread) __per_thread_##name[thread].v
-#define __get_thread_var(name) per_thread(name, smp_thread_id())
-
-#define init_per_thread(name, v) \
- do { \
- int __i_p_t_i; \
- for (__i_p_t_i = 0; __i_p_t_i < NR_THREADS; __i_p_t_i++) \
- per_thread(name, __i_p_t_i) = v; \
- } while (0)
-
-DEFINE_PER_THREAD(int, smp_processor_id);
-
-/*
- * Bug checks.
- */
-
-#define BUG_ON(c) do { if (!(c)) abort(); } while (0)
-
-/*
- * Initialization -- Must be called before calling any primitives.
- */
-
-static void smp_init(void)
-{
- int i;
-
- spin_lock_init(&__thread_id_map_mutex);
- __thread_id_map[0] = pthread_self();
- for (i = 1; i < NR_THREADS; i++)
- __thread_id_map[i] = __THREAD_ID_MAP_EMPTY;
- init_per_thread(smp_processor_id, 0);
- if (pthread_key_create(&thread_id_key, NULL) != 0) {
- perror("pthread_key_create");
- exit(-1);
- }
-}
-
-#endif
--- /dev/null
+AM_LDFLAGS=-lpthread
+AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g
+
+noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \
+ test_urcu_signal test_urcu_signal_dynamic_link test_urcu_signal_timing \
+ test_rwlock_timing test_rwlock test_perthreadlock_timing \
+ test_perthreadlock test_urcu_yield test_urcu_signal_yield test_urcu_mb \
+ test_urcu_qsbr_timing test_urcu_qsbr \
+ test_mutex test_looplen test_urcu_gc test_urcu_signal_gc \
+ test_urcu_lgc \
+ test_urcu_mb_gc test_urcu_qsbr_gc test_urcu_qsbr_lgc test_urcu_signal_lgc \
+ test_urcu_mb_lgc test_urcu_qsbr_dynamic_link test_urcu_defer \
+ test_urcu_assign test_urcu_assign_dynamic_link \
+ test_urcu_bp test_urcu_bp_dynamic_link test_cycles_per_loop \
+ test_urcu_lfq test_urcu_wfq test_urcu_lfs test_urcu_wfs \
+ test_urcu_lfs_rcu \
+ test_urcu_wfcq \
+ test_urcu_wfq_dynlink test_urcu_wfs_dynlink \
+ test_urcu_wfcq_dynlink \
+ test_urcu_lfq_dynlink test_urcu_lfs_dynlink test_urcu_hash \
+ test_urcu_lfs_rcu_dynlink
+
+if COMPAT_ARCH
+COMPAT=$(top_srcdir)/compat_arch_@ARCHTYPE@.c
+else
+COMPAT=
+endif
+
+if COMPAT_FUTEX
+COMPAT+=$(top_srcdir)/compat_futex.c
+endif
+
+URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_MB uses urcu.c but -DRCU_MB must be defined
+URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined
+URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+
+URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
+URCU_LIB=$(top_builddir)/liburcu.la
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+
+EXTRA_DIST = *.sh
+
+test_urcu_SOURCES = test_urcu.c $(URCU)
+
+test_urcu_dynamic_link_SOURCES = test_urcu.c $(URCU)
+test_urcu_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+
+test_urcu_timing_SOURCES = test_urcu_timing.c $(URCU)
+
+test_urcu_yield_SOURCES = test_urcu.c $(URCU)
+test_urcu_yield_CFLAGS = -DDEBUG_YIELD $(AM_CFLAGS)
+
+
+test_urcu_qsbr_SOURCES = test_urcu_qsbr.c $(URCU_QSBR)
+
+test_urcu_qsbr_timing_SOURCES = test_urcu_qsbr_timing.c $(URCU_QSBR)
+
+
+test_urcu_mb_SOURCES = test_urcu.c $(URCU_MB)
+test_urcu_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS)
+
+
+test_urcu_signal_SOURCES = test_urcu.c $(URCU_SIGNAL)
+test_urcu_signal_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
+
+test_urcu_signal_dynamic_link_SOURCES = test_urcu.c $(URCU_SIGNAL)
+test_urcu_signal_dynamic_link_CFLAGS = -DRCU_SIGNAL -DDYNAMIC_LINK_TEST \
+ $(AM_CFLAGS)
+
+test_urcu_signal_timing_SOURCES = test_urcu_timing.c $(URCU_SIGNAL)
+test_urcu_signal_timing_CFLAGS= -DRCU_SIGNAL $(AM_CFLAGS)
+
+test_urcu_signal_yield_SOURCES = test_urcu.c $(URCU_SIGNAL)
+test_urcu_signal_yield_CFLAGS = -DRCU_SIGNAL -DDEBUG_YIELD $(AM_CFLAGS)
+
+test_rwlock_timing_SOURCES = test_rwlock_timing.c $(URCU_SIGNAL)
+
+test_rwlock_SOURCES = test_rwlock.c $(URCU_SIGNAL)
+
+test_perthreadlock_timing_SOURCES = test_perthreadlock_timing.c $(URCU_SIGNAL)
+
+test_perthreadlock_SOURCES = test_perthreadlock.c $(URCU_SIGNAL)
+
+test_mutex_SOURCES = test_mutex.c $(URCU)
+
+test_looplen_SOURCES = test_looplen.c
+
+test_urcu_gc_SOURCES = test_urcu_gc.c $(URCU)
+
+test_urcu_signal_gc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL)
+test_urcu_signal_gc_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
+
+test_urcu_mb_gc_SOURCES = test_urcu_gc.c $(URCU_MB)
+test_urcu_mb_gc_CFLAGS = -DRCU_MB $(AM_CFLAGS)
+
+test_urcu_qsbr_gc_SOURCES = test_urcu_qsbr_gc.c $(URCU_QSBR)
+
+test_urcu_qsbr_lgc_SOURCES = test_urcu_qsbr_gc.c $(URCU_QSBR)
+test_urcu_qsbr_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS)
+
+test_urcu_lgc_SOURCES = test_urcu_gc.c $(URCU)
+test_urcu_lgc_CFLAGS = -DTEST_LOCAL_GC $(AM_CFLAGS)
+
+test_urcu_signal_lgc_SOURCES = test_urcu_gc.c $(URCU_SIGNAL)
+test_urcu_signal_lgc_CFLAGS = -DRCU_SIGNAL -DTEST_LOCAL_GC $(AM_CFLAGS)
+
+test_urcu_mb_lgc_SOURCES = test_urcu_gc.c $(URCU_MB)
+test_urcu_mb_lgc_CFLAGS = -DTEST_LOCAL_GC -DRCU_MB $(AM_CFLAGS)
+
+test_urcu_qsbr_dynamic_link_SOURCES = test_urcu_qsbr.c $(URCU_QSBR)
+test_urcu_qsbr_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+
+test_urcu_defer_SOURCES = test_urcu_defer.c $(URCU_DEFER)
+
+test_cycles_per_loop_SOURCES = test_cycles_per_loop.c
+
+test_urcu_assign_SOURCES = test_urcu_assign.c $(URCU)
+
+test_urcu_assign_dynamic_link_SOURCES = test_urcu_assign.c $(URCU)
+test_urcu_assign_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+
+test_urcu_bp_SOURCES = test_urcu_bp.c $(URCU_BP)
+
+test_urcu_bp_dynamic_link_SOURCES = test_urcu_bp.c $(URCU_BP)
+test_urcu_bp_dynamic_link_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+
+test_urcu_lfq_SOURCES = test_urcu_lfq.c $(URCU)
+test_urcu_lfq_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_lfq_dynlink_SOURCES = test_urcu_lfq.c $(URCU)
+test_urcu_lfq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_lfq_dynlink_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_wfq_SOURCES = test_urcu_wfq.c $(COMPAT)
+test_urcu_wfq_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_wfq_dynlink_SOURCES = test_urcu_wfq.c
+test_urcu_wfq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_wfq_dynlink_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_wfcq_SOURCES = test_urcu_wfcq.c $(COMPAT)
+test_urcu_wfcq_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_wfcq_dynlink_SOURCES = test_urcu_wfcq.c
+test_urcu_wfcq_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_wfcq_dynlink_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_lfs_SOURCES = test_urcu_lfs.c $(URCU)
+test_urcu_lfs_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_lfs_rcu_SOURCES = test_urcu_lfs_rcu.c $(URCU)
+test_urcu_lfs_rcu_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_lfs_dynlink_SOURCES = test_urcu_lfs.c $(URCU)
+test_urcu_lfs_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_lfs_dynlink_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_lfs_rcu_dynlink_SOURCES = test_urcu_lfs_rcu.c $(URCU)
+test_urcu_lfs_rcu_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_lfs_rcu_dynlink_LDADD = $(URCU_CDS_LIB)
+
+test_urcu_wfs_SOURCES = test_urcu_wfs.c $(COMPAT)
+test_urcu_wfs_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_wfs_dynlink_SOURCES = test_urcu_wfs.c
+test_urcu_wfs_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_wfs_dynlink_LDADD = $(URCU_COMMON_LIB)
+
+test_urcu_hash_SOURCES = test_urcu_hash.c test_urcu_hash.h \
+ test_urcu_hash_rw.c test_urcu_hash_unique.c $(COMPAT)
+test_urcu_hash_CFLAGS = -DRCU_QSBR $(AM_CFLAGS)
+test_urcu_hash_LDADD = $(URCU_QSBR_LIB) $(URCU_CDS_LIB)
+
+.PHONY: bench
+
+bench:
+ ./runall.sh
--- /dev/null
+#
+# This file is meant to be sourced from other tests scripts.
+#
+
+if [ -x "$URCU_TEST_TIME_BIN" ]; then
+ test_time_bin="$URCU_TEST_TIME_BIN"
+elif [ -x "/usr/bin/time" ]; then
+ test_time_bin="/usr/bin/time"
+else
+ test_time_bin=""
+fi
+
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+NUM_CPUS=8
+
+#extra options, e.g. for setting affinity on even CPUs :
+#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+#stride 1
+#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+#stride 2
+#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+#stride 4
+#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+#stride 8
+#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+
+#Vary update fraction
+#x: vary update fraction from 0 to 0.0001
+ #fix number of readers and reader C.S. length, vary delay between updates
+#y: ops/s
+
+rm -f runall.log
+rm -fr runall.detail.log
+
+
+echo Executing batch RCU test
+
+DURATION=10
+BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
+ 131072 262144"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f batch-rcu.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for BATCH_SIZE in ${BATCH_ARRAY}; do
+ echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
+ (./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log) || exit 1
+done
+
+#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE **
+EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
+
+echo Executing update fraction test
+
+DURATION=10
+WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
+ 65536 131072 262144 524288 1048576 2097152 4194304 8388608
+ 16777216 33554432 67108864 134217728"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f update-fraction.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for WDELAY in ${WDELAY_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
+ (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log) || exit 1
+done
+
+#Test scalability :
+# x: vary number of readers from 0 to num cpus
+# y: ops/s
+# 0 writer.
+
+echo Executing scalability test
+
+NR_WRITERS=0
+DURATION=10
+
+rm -f scalability.log
+
+for NR_READERS in $(seq 1 ${NUM_CPUS}); do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
+ (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log) || exit 1
+done
+
+
+# x: Vary reader C.S. length from 0 to 100 us
+# y: ops/s
+# 8 readers
+# 0 writers
+
+echo Executing reader C.S. length test
+
+NR_READERS=${NUM_CPUS}
+NR_WRITERS=0
+DURATION=10
+#in loops.
+READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
+
+rm -f readercslen.log
+
+for READERCSLEN in ${READERCSLEN_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log
+ (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log) || exit 1
+done
+
+echo Executing Hash table test
+./runhash.sh || exit 1
--- /dev/null
+#!/bin/sh
+
+# TODO: missing tests:
+# - send kill signals during tests to change the behavior between
+# add/remove/random
+# - validate that "nr_leaked" is always 0 in SUMMARY for all tests
+
+# 30 seconds per test
+TIME_UNITS=30
+
+TESTPROG=./test_urcu_hash
+
+#thread multiplier
+THREAD_MUL=1
+
+EXTRA_PARAMS=-v
+
+# ** test update coherency with single-value table
+
+# rw test, single key, replace and del randomly, 4 threads, auto resize.
+# key range: init, lookup, and update: 0 to 0
+${TESTPROG} 0 $((4*${THREAD_MUL})) ${TIME_UNITS} -A -s -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
+
+# rw test, single key, add unique and del randomly, 4 threads, auto resize.
+# key range: init, lookup, and update: 0 to 0
+${TESTPROG} 0 $((4*${THREAD_MUL})) ${TIME_UNITS} -A -u -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
+
+# rw test, single key, replace and del randomly, 2 lookup threads, 2 update threads, auto resize.
+# key range: init, lookup, and update: 0 to 0
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -s -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
+
+# rw test, single key, add and del randomly, 2 lookup threads, 2 update threads, auto resize.
+# key range: init, lookup, and update: 0 to 0
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
+
+
+# ** test updates vs lookups with default table
+
+# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, lookup, and update: 0 to 999999
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, lookup, and update: 0 to 999999
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -s ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add_unique and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, lookup, and update: 0 to 999999
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -u ${EXTRA_PARAMS} || exit 1
+
+
+# test memory management backends
+
+# rw test, 2 lookup, 2 update threads, add only, auto resize.
+# max buckets: 1048576
+# key range: init, lookup, and update: 0 to 99999999
+# mm backend: "order"
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
+ -M 100000000 -N 100000000 -O 100000000 -B order ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add only, auto resize.
+# max buckets: 1048576
+# key range: init, lookup, and update: 0 to 99999999
+# mm backend: "chunk"
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
+ -M 100000000 -N 100000000 -O 100000000 -B chunk ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add only, auto resize.
+# max buckets: 1048576
+# key range: init, lookup, and update: 0 to 99999999
+# mm backend: "mmap"
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
+ -M 100000000 -N 100000000 -O 100000000 -B mmap ${EXTRA_PARAMS} || exit 1
+
+
+# ** key range tests
+
+# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, and update: 0 to 999999
+# key range: lookup: 1000000 to 1999999
+# NOTE: reader threads in this test should never have a successful
+# lookup. TODO
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -R 1000000 ${EXTRA_PARAMS} || exit 1
+
+# ** small key range
+
+# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, update, and lookups: 0 to 9
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -M 10 -N 10 -O 10 ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add_unique and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, update, and lookups: 0 to 9
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -M 10 -N 10 -O 10 -u ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
+# max 1048576 buckets
+# key range: init, update, and lookups: 0 to 9
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -M 10 -N 10 -O 10 -s ${EXTRA_PARAMS} || exit 1
+
+# ** lookup for known keys
+
+# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
+# max 1048576 buckets
+# lookup range is entirely populated.
+# key range: init, and lookups: 0 to 9
+# key range: updates: 10 to 19
+# NOTE: reader threads in this test should always have successful
+# lookups. TODO
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -M 10 -N 10 -O 10 -R 0 -T 0 -S 10 -k 10 -s ${EXTRA_PARAMS} || exit 1
+
+# ** Uniqueness test
+
+# rw test, 2 lookup, 2 update threads, add_unique, add_replace and del randomly, auto resize.
+# max 1048576 buckets
+# asserts that no duplicates are observed by reader threads
+# standard length hash chains
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -U ${EXTRA_PARAMS} || exit 1
+
+# rw test, 2 lookup, 2 update threads, add_unique, add_replace and del randomly, auto resize.
+# max 1048576 buckets
+# asserts that no duplicates are observed by reader threads
+# create long hash chains: using modulo 4 on keys as hash
+${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
+ -U -C 4 ${EXTRA_PARAMS} || exit 1
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+NUM_CPUS=64
+
+#extra options, e.g. for setting affinity on even CPUs :
+EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+#stride 1
+#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+#stride 2
+#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+#stride 4
+#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+#stride 8
+#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+
+#Vary update fraction
+#x: vary update fraction from 0 to 0.0001
+ #fix number of readers and reader C.S. length, vary delay between updates
+#y: ops/s
+
+rm -f runall.log
+rm -fr runall.detail.log
+
+
+echo Executing batch RCU test
+
+DURATION=10
+BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
+ 131072 262144"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f batch-rcu.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for BATCH_SIZE in ${BATCH_ARRAY}; do
+ echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
+ ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log
+done
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+NUM_CPUS=64
+
+#extra options, e.g. for setting affinity on even CPUs :
+EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+#stride 1
+#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+#stride 2
+#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+#stride 4
+#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+#stride 8
+#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+
+#Vary update fraction
+#x: vary update fraction from 0 to 0.0001
+ #fix number of readers and reader C.S. length, vary delay between updates
+#y: ops/s
+
+rm -f runall.log
+rm -fr runall.detail.log
+
+#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT **
+EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
+
+echo Executing update fraction test
+
+DURATION=10
+WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
+ 65536 131072 262144 524288 1048576 2097152 4194304 8388608
+ 16777216 33554432 67108864 134217728"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f update-fraction.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for WDELAY in ${WDELAY_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log
+done
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+NUM_CPUS=64
+
+#extra options, e.g. for setting affinity on even CPUs :
+EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+#stride 1
+#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+#stride 2
+#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+#stride 4
+#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+#stride 8
+#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+
+#Vary update fraction
+#x: vary update fraction from 0 to 0.0001
+ #fix number of readers and reader C.S. length, vary delay between updates
+#y: ops/s
+
+rm -f runall.log
+rm -fr runall.detail.log
+
+#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT **
+EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
+
+#Test scalability :
+# x: vary number of readers from 0 to num cpus
+# y: ops/s
+# 0 writer.
+
+echo Executing scalability test
+
+NR_WRITERS=0
+DURATION=10
+
+rm -f scalability.log
+
+for NR_READERS in $(seq 1 ${NUM_CPUS}); do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log
+done
+
+
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+export NUM_CPUS=8
+
+#extra options, e.g. for setting affinity on even CPUs :
+#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+rm -f *.log
+
+#stride 1
+export EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+sh subphase4.sh $*
+mkdir ppc64-8cores-stride1
+mv *.log ppc64-8cores-stride1/
+
+
+#stride 2
+export EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+sh subphase4.sh $*
+mkdir ppc64-8cores-stride2
+mv *.log ppc64-8cores-stride2/
+
+
+#stride 4
+export EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+sh subphase4.sh $*
+mkdir ppc64-8cores-stride4
+mv *.log ppc64-8cores-stride4/
+
+
+#stride 8
+export EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+sh subphase4.sh $*
+mkdir ppc64-8cores-stride8
+mv *.log ppc64-8cores-stride8/
--- /dev/null
+# test run after write-size update
+
+sh runpaul-phase1.sh
+mkdir runpaul-phase1
+mv *.log runpaul-phase1/
+
+sh runpaul-phase2.sh
+mkdir runpaul-phase2
+mv *.log runpaul-phase2/
+
+sh runpaul-phase4.sh
--- /dev/null
+sh runpaul-phase1.sh
+mkdir runpaul-phase1
+mv *.log runpaul-phase1/
+
+sh runpaul-phase2.sh
+mkdir runpaul-phase2
+mv *.log runpaul-phase2/
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+export NUM_CPUS=64
+#export NUM_CPUS=8
+
+#extra options, e.g. for setting affinity on even CPUs :
+EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+#EXTRA_OPTS=$(for a in $(seq 0 1 7); do echo -n "-a ${a} "; done)
+
+rm -f *.log
+
+# x: Vary writer C.S. length from 0 to 100 us
+# y: reads/s
+# 4 readers
+# 4 writers
+
+echo Executing writer C.S. length test
+
+NR_READERS=$((${NUM_CPUS} / 2))
+NR_WRITERS=$((${NUM_CPUS} / 2))
+DURATION=10
+WDELAY=10
+#in loops.
+WRITERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
+
+rm -f writercslen.log
+
+for WRITERCSLEN in ${WRITERCSLEN_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -d ${WDELAY} -e ${WRITERCSLEN} | tee -a writercslen.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -d ${WDELAY} -e ${WRITERCSLEN} | tee -a writercslen.log
+done
+
+
+
+mkdir ppc64-writercslen
+mv *.log ppc64-writercslen/
+#mkdir xeon-writercslen
+#mv *.log xeon-writercslen/
--- /dev/null
+#!/bin/sh
+
+. ./common.sh
+
+log_file="runall.detail.log"
+
+# Check if time bin is non-empty
+if [ -n "$test_time_bin" ]; then
+ time_command="$test_time_bin -a -o $log_file"
+else
+ time_command=""
+fi
+
+#for a in test_urcu_gc test_urcu_gc_mb test_urcu_qsbr_gc; do
+for a in test_urcu_gc; do
+ echo "./${a} $*" | tee -a "$log_file"
+ $time_command ./${a} $*
+done
+
--- /dev/null
+#!/bin/sh
+
+. ./common.sh
+
+log_file="runall.detail.log"
+
+# Check if time bin is non-empty
+if [ -n "$test_time_bin" ]; then
+ time_command="$test_time_bin -a -o $log_file"
+else
+ time_command=""
+fi
+
+for a in test_urcu_gc test_urcu_signal_gc test_urcu_mb_gc test_urcu_qsbr_gc \
+ test_urcu_lgc test_urcu_signal_lgc test_urcu_mb_lgc test_urcu_qsbr_lgc \
+ test_urcu test_urcu_signal test_urcu_mb test_urcu_qsbr \
+ test_rwlock test_perthreadlock test_mutex; do
+ echo "./${a} $*" | tee -a "$log_file"
+ $time_command ./${a} $*
+done
+
--- /dev/null
+#!/bin/sh
+
+#run all tests
+
+#set to number of active CPUS
+#NUM_CPUS=8
+
+#extra options, e.g. for setting affinity on even CPUs :
+#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
+
+#ppc64 striding, use with NUM_CPUS=8
+
+#stride 1
+#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
+#stride 2
+#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
+#stride 4
+#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
+#stride 8
+#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
+
+#Vary update fraction
+#x: vary update fraction from 0 to 0.0001
+ #fix number of readers and reader C.S. length, vary delay between updates
+#y: ops/s
+
+rm -f runall.log
+rm -fr runall.detail.log
+
+
+echo Executing batch RCU test
+
+DURATION=10
+BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
+ 131072 262144"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f batch-rcu.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for BATCH_SIZE in ${BATCH_ARRAY}; do
+ echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
+ ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log
+done
+
+#setting gc each 4096. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE **
+EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
+
+echo Executing update fraction test
+
+DURATION=10
+WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
+ 65536 131072 262144 524288 1048576 2097152 4194304 8388608
+ 16777216 33554432 67108864 134217728"
+NR_WRITERS=$((${NUM_CPUS} / 2))
+
+rm -f update-fraction.log
+
+NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
+for WDELAY in ${WDELAY_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log
+done
+
+#Test scalability :
+# x: vary number of readers from 0 to num cpus
+# y: ops/s
+# 0 writer.
+
+echo Executing scalability test
+
+NR_WRITERS=0
+DURATION=10
+
+rm -f scalability.log
+
+for NR_READERS in $(seq 1 ${NUM_CPUS}); do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log
+done
+
+
+# x: Vary reader C.S. length from 0 to 100 us
+# y: ops/s
+# 8 readers
+# 0 writers
+
+echo Executing reader C.S. length test
+
+NR_READERS=${NUM_CPUS}
+NR_WRITERS=0
+DURATION=10
+#in loops.
+READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
+
+rm -f readercslen.log
+
+for READERCSLEN in ${READERCSLEN_ARRAY}; do
+ echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log
+ ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log
+done
--- /dev/null
+/*
+ * test_cycles_per_loop.c
+ *
+ * Userspace RCU library - test cycles per loop
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <urcu/arch.h>
+#include <stdio.h>
+
+#define NR_LOOPS 1000000UL
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+int main()
+{
+ cycles_t time1, time2;
+
+ time1 = caa_get_cycles();
+ loop_sleep(NR_LOOPS);
+ time2 = caa_get_cycles();
+ printf("CPU clock cycles per loop: %g\n", (time2 - time1) /
+ (double)NR_LOOPS);
+ return 0;
+}
--- /dev/null
+/*
+ * test_looplen.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sched.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define debug_yield_read()
+#endif
+#include <urcu.h>
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+#define LOOPS 1048576
+#define TESTS 10
+
+int main(int argc, char **argv)
+{
+ unsigned long i;
+ cycles_t time1, time2;
+ cycles_t time_tot = 0;
+ double cpl;
+
+ for (i = 0; i < TESTS; i++) {
+ time1 = caa_get_cycles();
+ loop_sleep(LOOPS);
+ time2 = caa_get_cycles();
+ time_tot += time2 - time1;
+ }
+ cpl = ((double)time_tot) / (double)TESTS / (double)LOOPS;
+
+ printf("CALIBRATION : %g cycles per loop\n", cpl);
+ printf("time_tot = %llu, LOOPS = %d, TESTS = %d\n",
+ time_tot, LOOPS, TESTS);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+static pthread_mutex_t lock;
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static volatile struct test_array test_array = { 8 };
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_reads;
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *data)
+{
+ unsigned long tidx = (unsigned long)data;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+
+ for (;;) {
+ pthread_mutex_lock(&lock);
+ assert(test_array.a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ pthread_mutex_unlock(&lock);
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ tot_nr_reads[tidx] = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *data)
+{
+ unsigned long wtidx = (unsigned long)data;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ pthread_mutex_lock(&lock);
+ test_array.a = 0;
+ test_array.a = 8;
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ pthread_mutex_unlock(&lock);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ cmm_smp_mb();
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ yield_active |= YIELD_READ;
+ break;
+ case 'w':
+ yield_active |= YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+ tot_nr_reads = calloc(nr_readers, sizeof(*tot_nr_reads));
+ tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += tot_nr_reads[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += tot_nr_writes[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ free(tot_nr_reads);
+ free(tot_nr_writes);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+struct per_thread_lock {
+ pthread_mutex_t lock;
+} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); /* cache-line aligned */
+
+static struct per_thread_lock *per_thread_lock;
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static volatile struct test_array test_array = { 8 };
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_reads;
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *data)
+{
+ unsigned long tidx = (unsigned long)data;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+
+ for (;;) {
+ pthread_mutex_lock(&per_thread_lock[tidx].lock);
+ assert(test_array.a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ pthread_mutex_unlock(&per_thread_lock[tidx].lock);
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ tot_nr_reads[tidx] = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *data)
+{
+ unsigned long wtidx = (unsigned long)data;
+ long tidx;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ for (tidx = 0; tidx < nr_readers; tidx++) {
+ pthread_mutex_lock(&per_thread_lock[tidx].lock);
+ }
+ test_array.a = 0;
+ test_array.a = 8;
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ for (tidx = (long)nr_readers - 1; tidx >= 0; tidx--) {
+ pthread_mutex_unlock(&per_thread_lock[tidx].lock);
+ }
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ cmm_smp_mb();
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ yield_active |= YIELD_READ;
+ break;
+ case 'w':
+ yield_active |= YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ tot_nr_reads = calloc(nr_readers, sizeof(*tot_nr_reads));
+ tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
+ per_thread_lock = calloc(nr_readers, sizeof(*per_thread_lock));
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_mutex_init(&per_thread_lock[i].lock, NULL);
+ if (err != 0)
+ exit(1);
+ }
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += tot_nr_reads[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += tot_nr_writes[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+
+ free(tid_reader);
+ free(tid_writer);
+ free(tot_nr_reads);
+ free(tot_nr_writes);
+ free(per_thread_lock);
+ return 0;
+}
--- /dev/null
+/*
+ * test_perthreadloc_timing.c
+ *
+ * Per thread locks - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+
+#include "thread-id.h"
+
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+static struct test_array test_array = { 8 };
+
+struct per_thread_lock {
+ pthread_mutex_t lock;
+} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); /* cache-line aligned */
+
+static struct per_thread_lock *per_thread_lock;
+
+#define OUTER_READ_LOOP 200U
+#define INNER_READ_LOOP 100000U
+#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
+
+#define OUTER_WRITE_LOOP 10U
+#define INNER_WRITE_LOOP 200U
+#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
+
+static int num_read;
+static int num_write;
+
+#define NR_READ num_read
+#define NR_WRITE num_write
+
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
+
+void *thr_reader(void *arg)
+{
+ int i, j;
+ cycles_t time1, time2;
+ long tidx = (long)arg;
+
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ sleep(2);
+
+ time1 = caa_get_cycles();
+ for (i = 0; i < OUTER_READ_LOOP; i++) {
+ for (j = 0; j < INNER_READ_LOOP; j++) {
+ pthread_mutex_lock(&per_thread_lock[tidx].lock);
+ assert(test_array.a == 8);
+ pthread_mutex_unlock(&per_thread_lock[tidx].lock);
+ }
+ }
+ time2 = caa_get_cycles();
+
+ reader_time[tidx] = time2 - time1;
+
+ sleep(2);
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *arg)
+{
+ int i, j;
+ long tidx;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ sleep(2);
+
+ for (i = 0; i < OUTER_WRITE_LOOP; i++) {
+ for (j = 0; j < INNER_WRITE_LOOP; j++) {
+ time1 = caa_get_cycles();
+ for (tidx = 0; tidx < NR_READ; tidx++) {
+ pthread_mutex_lock(&per_thread_lock[tidx].lock);
+ }
+ test_array.a = 8;
+ for (tidx = NR_READ - 1; tidx >= 0; tidx--) {
+ pthread_mutex_unlock(&per_thread_lock[tidx].lock);
+ }
+ time2 = caa_get_cycles();
+ writer_time[(unsigned long)arg] += time2 - time1;
+ usleep(1);
+ }
+ }
+
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ return ((void*)2);
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ int i;
+ cycles_t tot_rtime = 0;
+ cycles_t tot_wtime = 0;
+
+ if (argc < 2) {
+ printf("Usage : %s nr_readers nr_writers\n", argv[0]);
+ exit(-1);
+ }
+ num_read = atoi(argv[1]);
+ num_write = atoi(argv[2]);
+
+ reader_time = calloc(num_read, sizeof(*reader_time));
+ writer_time = calloc(num_write, sizeof(*writer_time));
+ tid_reader = calloc(num_read, sizeof(*tid_reader));
+ tid_writer = calloc(num_write, sizeof(*tid_writer));
+
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ per_thread_lock = malloc(sizeof(struct per_thread_lock) * NR_READ);
+
+ for (i = 0; i < NR_READ; i++) {
+ pthread_mutex_init(&per_thread_lock[i].lock, NULL);
+ }
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ sleep(10);
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_rtime += reader_time[i];
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_wtime += writer_time[i];
+ }
+ printf("Time per read : %g cycles\n",
+ (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
+ printf("Time per write : %g cycles\n",
+ (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
+ free(per_thread_lock);
+
+ free(reader_time);
+ free(writer_time);
+ free(tid_reader);
+ free(tid_writer);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static volatile struct test_array test_array = { 8 };
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+
+ for (;;) {
+ pthread_rwlock_rdlock(&lock);
+ assert(test_array.a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ pthread_rwlock_unlock(&lock);
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ pthread_rwlock_wrlock(&lock);
+ test_array.a = 0;
+ test_array.a = 8;
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ pthread_rwlock_unlock(&lock);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ *count = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ cmm_smp_mb();
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ yield_active |= YIELD_READ;
+ break;
+ case 'w':
+ yield_active |= YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+
+#include "thread-id.h"
+
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
+
+static struct test_array test_array = { 8 };
+
+#define OUTER_READ_LOOP 200U
+#define INNER_READ_LOOP 100000U
+#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
+
+#define OUTER_WRITE_LOOP 10U
+#define INNER_WRITE_LOOP 200U
+#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
+
+static int num_read;
+static int num_write;
+
+#define NR_READ num_read
+#define NR_WRITE num_write
+
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
+
+void *thr_reader(void *arg)
+{
+ int i, j;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ sleep(2);
+
+ time1 = caa_get_cycles();
+ for (i = 0; i < OUTER_READ_LOOP; i++) {
+ for (j = 0; j < INNER_READ_LOOP; j++) {
+ pthread_rwlock_rdlock(&lock);
+ assert(test_array.a == 8);
+ pthread_rwlock_unlock(&lock);
+ }
+ }
+ time2 = caa_get_cycles();
+
+ reader_time[(unsigned long)arg] = time2 - time1;
+
+ sleep(2);
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *arg)
+{
+ int i, j;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ sleep(2);
+
+ for (i = 0; i < OUTER_WRITE_LOOP; i++) {
+ for (j = 0; j < INNER_WRITE_LOOP; j++) {
+ time1 = caa_get_cycles();
+ pthread_rwlock_wrlock(&lock);
+ test_array.a = 8;
+ pthread_rwlock_unlock(&lock);
+ time2 = caa_get_cycles();
+ writer_time[(unsigned long)arg] += time2 - time1;
+ usleep(1);
+ }
+ }
+
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ return ((void*)2);
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ int i;
+ cycles_t tot_rtime = 0;
+ cycles_t tot_wtime = 0;
+
+ if (argc < 2) {
+ printf("Usage : %s nr_readers nr_writers\n", argv[0]);
+ exit(-1);
+ }
+ num_read = atoi(argv[1]);
+ num_write = atoi(argv[2]);
+
+ reader_time = calloc(num_read, sizeof(*reader_time));
+ writer_time = calloc(num_write, sizeof(*writer_time));
+ tid_reader = calloc(num_read, sizeof(*tid_reader));
+ tid_writer = calloc(num_write, sizeof(*tid_writer));
+
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ sleep(10);
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_rtime += reader_time[i];
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_wtime += writer_time[i];
+ }
+ printf("Time per read : %g cycles\n",
+ (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
+ printf("Time per write : %g cycles\n",
+ (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
+
+ free(reader_time);
+ free(writer_time);
+ free(tid_reader);
+ free(tid_writer);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu.h>
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static int *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ int *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+ assert(!rcu_read_ongoing());
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ assert(rcu_read_ongoing());
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(*local_ptr == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ /* test extra thread registration */
+ rcu_register_thread();
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *_count)
+{
+ unsigned long long *count = _count;
+ int *new, *old;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ new = malloc(sizeof(int));
+ assert(new);
+ *new = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ synchronize_rcu();
+ if (old)
+ *old = 0;
+ free(old);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ *count = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+ free(test_rcu_pointer);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_assign.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static struct test_array *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+/*
+ * malloc/free are reusing memory areas too quickly, which does not let us
+ * test races appropriately. Use a large circular array for allocations.
+ * ARRAY_SIZE is larger than nr_writers, and we keep the mutex across
+ * both alloc and free, which insures we never run over our tail.
+ */
+#define ARRAY_SIZE (1048576 * nr_writers)
+#define ARRAY_POISON 0xDEADBEEF
+static int array_index;
+static struct test_array *test_array;
+
+static struct test_array *test_array_alloc(void)
+{
+ struct test_array *ret;
+ int index;
+
+ index = array_index % ARRAY_SIZE;
+ assert(test_array[index].a == ARRAY_POISON ||
+ test_array[index].a == 0);
+ ret = &test_array[index];
+ array_index++;
+ if (array_index == ARRAY_SIZE)
+ array_index = 0;
+ return ret;
+}
+
+static void test_array_free(struct test_array *ptr)
+{
+ if (!ptr)
+ return;
+ ptr->a = ARRAY_POISON;
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct test_array *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(local_ptr->a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *_count)
+{
+ unsigned long long *count = _count;
+ struct test_array *new, *old;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_copy_mutex_lock();
+ new = test_array_alloc();
+ new->a = 8;
+ old = test_rcu_pointer;
+ rcu_assign_pointer(test_rcu_pointer, new);
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ synchronize_rcu();
+ if (old)
+ old->a = 0;
+ test_array_free(old);
+ rcu_copy_mutex_unlock();
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ *count = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ test_array = calloc(1, sizeof(*test_array) * ARRAY_SIZE);
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+ test_array_free(test_rcu_pointer);
+ free(test_array);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu-bp.h>
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static int *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ int *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+ assert(!rcu_read_ongoing());
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ assert(rcu_read_ongoing());
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(*local_ptr == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *_count)
+{
+ unsigned long long *count = _count;
+ int *new, *old;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ new = malloc(sizeof(int));
+ *new = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ synchronize_rcu();
+ if (old)
+ *old = 0;
+ free(old);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ *count = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+ free(test_rcu_pointer);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_defer.c
+ *
+ * Userspace RCU library - test program (with automatic reclamation)
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu.h>
+#include <urcu-defer.h>
+
+struct test_array {
+ int a;
+};
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static struct test_array *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct test_array *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(local_ptr->a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+static void test_cb2(void *data)
+{
+}
+
+static void test_cb1(void *data)
+{
+}
+
+void *thr_writer(void *data)
+{
+ unsigned long wtidx = (unsigned long)data;
+ struct test_array *new, *old = NULL;
+ int ret;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ ret = rcu_defer_register_thread();
+ if (ret) {
+ printf("Error in rcu_defer_register_thread\n");
+ exit(-1);
+ }
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ new = malloc(sizeof(*new));
+ new->a = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ defer_rcu(free, old);
+ defer_rcu(test_cb1, old);
+ defer_rcu(test_cb1, (void *)-2L);
+ defer_rcu(test_cb1, (void *)-2L);
+ defer_rcu(test_cb1, old);
+ defer_rcu(test_cb2, (void *)-2L);
+ defer_rcu(test_cb2, (void *)-4L);
+ defer_rcu(test_cb2, (void *)-2L);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ rcu_defer_unregister_thread();
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += tot_nr_writes[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(tot_nr_writes);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_gc.c
+ *
+ * Userspace RCU library - test program (with batch reclamation)
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_array {
+ int a;
+};
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static struct test_array *test_rcu_pointer;
+
+static unsigned int reclaim_batch = 1;
+
+struct reclaim_queue {
+ void **queue; /* Beginning of queue */
+ void **head; /* Insert position */
+};
+
+static struct reclaim_queue *pending_reclaims;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct test_array *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(local_ptr->a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+static void rcu_gc_clear_queue(unsigned long wtidx)
+{
+ void **p;
+
+ /* Wait for Q.S and empty queue */
+ synchronize_rcu();
+
+ for (p = pending_reclaims[wtidx].queue;
+ p < pending_reclaims[wtidx].head; p++) {
+ /* poison */
+ if (*p)
+ ((struct test_array *)*p)->a = 0;
+ free(*p);
+ }
+ pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue;
+}
+
+/* Using per-thread queue */
+static void rcu_gc_reclaim(unsigned long wtidx, void *old)
+{
+ /* Queue pointer */
+ *pending_reclaims[wtidx].head = old;
+ pending_reclaims[wtidx].head++;
+
+ if (caa_likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue
+ < reclaim_batch))
+ return;
+
+ rcu_gc_clear_queue(wtidx);
+}
+
+void *thr_writer(void *data)
+{
+ unsigned long wtidx = (unsigned long)data;
+#ifdef TEST_LOCAL_GC
+ struct test_array *old = NULL;
+#else
+ struct test_array *new, *old;
+#endif
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+#ifndef TEST_LOCAL_GC
+ new = malloc(sizeof(*new));
+ new->a = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+#endif
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ rcu_gc_reclaim(wtidx, old);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'b':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ reclaim_batch = atol(argv[++i]);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
+ pending_reclaims = calloc(nr_writers, sizeof(*pending_reclaims));
+ if (reclaim_batch * sizeof(*pending_reclaims[i].queue)
+ < CAA_CACHE_LINE_SIZE)
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].queue = calloc(1, CAA_CACHE_LINE_SIZE);
+ else
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].queue = calloc(reclaim_batch,
+ sizeof(*pending_reclaims[i].queue));
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].head = pending_reclaims[i].queue;
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += tot_nr_writes[i];
+ rcu_gc_clear_queue(i);
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
+ "batch %u\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes, reclaim_batch);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(tot_nr_writes);
+ for (i = 0; i < nr_writers; i++)
+ free(pending_reclaims[i].queue);
+ free(pending_reclaims);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_hash.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "test_urcu_hash.h"
+
+enum test_hash {
+ TEST_HASH_RW,
+ TEST_HASH_UNIQUE,
+};
+
+struct test_hash_cb {
+ void (*sigusr1)(int signo);
+ void (*sigusr2)(int signo);
+ void *(*thr_reader)(void *_count);
+ void *(*thr_writer)(void *_count);
+ int (*populate_hash)(void);
+};
+
+static
+struct test_hash_cb test_hash_cb[] = {
+ [TEST_HASH_RW] = {
+ test_hash_rw_sigusr1_handler,
+ test_hash_rw_sigusr2_handler,
+ test_hash_rw_thr_reader,
+ test_hash_rw_thr_writer,
+ test_hash_rw_populate_hash,
+ },
+ [TEST_HASH_UNIQUE] = {
+ test_hash_unique_sigusr1_handler,
+ test_hash_unique_sigusr2_handler,
+ test_hash_unique_thr_reader,
+ test_hash_unique_thr_writer,
+ test_hash_unique_populate_hash,
+ },
+
+};
+
+static enum test_hash test_choice = TEST_HASH_RW;
+
+void (*get_sigusr1_cb(void))(int)
+{
+ return test_hash_cb[test_choice].sigusr1;
+}
+
+void (*get_sigusr2_cb(void))(int)
+{
+ return test_hash_cb[test_choice].sigusr2;
+}
+
+void *(*get_thr_reader_cb(void))(void *)
+{
+ return test_hash_cb[test_choice].thr_reader;
+}
+
+void *(*get_thr_writer_cb(void))(void *)
+{
+ return test_hash_cb[test_choice].thr_writer;
+}
+
+int (*get_populate_hash_cb(void))(void)
+{
+ return test_hash_cb[test_choice].populate_hash;
+}
+
+DEFINE_URCU_TLS(unsigned int, rand_lookup);
+DEFINE_URCU_TLS(unsigned long, nr_add);
+DEFINE_URCU_TLS(unsigned long, nr_addexist);
+DEFINE_URCU_TLS(unsigned long, nr_del);
+DEFINE_URCU_TLS(unsigned long, nr_delnoent);
+DEFINE_URCU_TLS(unsigned long, lookup_fail);
+DEFINE_URCU_TLS(unsigned long, lookup_ok);
+
+struct cds_lfht *test_ht;
+
+volatile int test_go, test_stop;
+
+unsigned long wdelay;
+
+unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+unsigned long rduration;
+
+unsigned long init_hash_size = DEFAULT_HASH_SIZE;
+unsigned long min_hash_alloc_size = DEFAULT_MIN_ALLOC_SIZE;
+unsigned long max_hash_buckets_size = (1UL << 20);
+unsigned long init_populate;
+int opt_auto_resize;
+int add_only, add_unique, add_replace;
+const struct cds_lfht_mm_type *memory_backend;
+
+unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
+unsigned long init_pool_size = DEFAULT_RAND_POOL,
+ lookup_pool_size = DEFAULT_RAND_POOL,
+ write_pool_size = DEFAULT_RAND_POOL;
+int validate_lookup;
+unsigned long nr_hash_chains; /* 0: normal table, other: number of hash chains */
+
+int count_pipe[2];
+
+int verbose_mode;
+
+unsigned int cpu_affinities[NR_CPUS];
+unsigned int next_aff = 0;
+int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+DEFINE_URCU_TLS(unsigned long long, nr_writes);
+DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+unsigned int nr_readers;
+unsigned int nr_writers;
+
+static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+unsigned long test_compare(const void *key1, size_t key1_len,
+ const void *key2, size_t key2_len)
+{
+ if (caa_unlikely(key1_len != key2_len))
+ return -1;
+ assert(key1_len == sizeof(unsigned long));
+ if (key1 == key2)
+ return 0;
+ else
+ return 1;
+}
+
+void *thr_count(void *arg)
+{
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "counter", urcu_get_thread_id());
+
+ rcu_register_thread();
+
+ for (;;) {
+ unsigned long count;
+ long approx_before, approx_after;
+ ssize_t len;
+ char buf[1];
+
+ rcu_thread_offline();
+ len = read(count_pipe[0], buf, 1);
+ rcu_thread_online();
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ if (len != 1)
+ continue;
+ /* Accounting */
+ printf("Counting nodes... ");
+ fflush(stdout);
+ rcu_read_lock();
+ cds_lfht_count_nodes(test_ht, &approx_before, &count,
+ &approx_after);
+ rcu_read_unlock();
+ printf("done.\n");
+ printf("Approximation before node accounting: %ld nodes.\n",
+ approx_before);
+ printf("Accounting of nodes in the hash table: "
+ "%lu nodes.\n",
+ count);
+ printf("Approximation after node accounting: %ld nodes.\n",
+ approx_after);
+ }
+ rcu_unregister_thread();
+ return NULL;
+}
+
+void free_node_cb(struct rcu_head *head)
+{
+ struct lfht_test_node *node =
+ caa_container_of(head, struct lfht_test_node, head);
+ free(node);
+}
+
+static
+void test_delete_all_nodes(struct cds_lfht *ht)
+{
+ struct cds_lfht_iter iter;
+ struct lfht_test_node *node;
+ unsigned long count = 0;
+
+ cds_lfht_for_each_entry(ht, &iter, node, node) {
+ int ret;
+
+ ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
+ assert(!ret);
+ call_rcu(&node->head, free_node_cb);
+ count++;
+ }
+ printf("deleted %lu nodes.\n", count);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf(" [-h size] (initial number of buckets)\n");
+ printf(" [-m size] (minimum number of allocated buckets)\n");
+ printf(" [-n size] (maximum number of buckets)\n");
+printf(" [not -u nor -s] Add entries (supports redundant keys).\n");
+ printf(" [-u] Uniquify add (no redundant keys).\n");
+ printf(" [-s] Replace (swap) entries.\n");
+ printf(" [-i] Add only (no removal).\n");
+ printf(" [-k nr_nodes] Number of nodes to insert initially.\n");
+ printf(" [-A] Automatically resize hash table.\n");
+ printf(" [-B order|chunk|mmap] Specify the memory backend.\n");
+ printf(" [-R offset] Lookup pool offset.\n");
+ printf(" [-S offset] Write pool offset.\n");
+ printf(" [-T offset] Init pool offset.\n");
+ printf(" [-M size] Lookup pool size.\n");
+ printf(" [-N size] Write pool size.\n");
+ printf(" [-O size] Init pool size.\n");
+ printf(" [-V] Validate lookups of init values.\n");
+ printf(" (use with filled init pool, same lookup range,\n");
+ printf(" with different write range)\n");
+ printf(" [-U] Uniqueness test.\n");
+ printf(" [-C] Number of hash chains.\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ pthread_t *tid_reader, *tid_writer;
+ pthread_t tid_count;
+ void *tret;
+ unsigned long long *count_reader;
+ struct wr_count *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0,
+ tot_add = 0, tot_add_exist = 0, tot_remove = 0;
+ unsigned long count;
+ long approx_before, approx_after;
+ int i, a, ret, err, mainret = 0;
+ struct sigaction act;
+ unsigned int remain;
+ unsigned int nr_readers_created = 0, nr_writers_created = 0;
+ long long nr_leaked;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ yield_active |= YIELD_READ;
+ break;
+ case 'w':
+ yield_active |= YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ case 'h':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ init_hash_size = atol(argv[++i]);
+ break;
+ case 'm':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ min_hash_alloc_size = atol(argv[++i]);
+ break;
+ case 'n':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ max_hash_buckets_size = atol(argv[++i]);
+ break;
+ case 'u':
+ if (add_replace) {
+ printf("Please specify at most one of -s or -u.\n");
+ exit(-1);
+ }
+ add_unique = 1;
+ break;
+ case 's':
+ if (add_unique) {
+ printf("Please specify at most one of -s or -u.\n");
+ exit(-1);
+ }
+ add_replace = 1;
+ break;
+ case 'i':
+ add_only = 1;
+ break;
+ case 'k':
+ init_populate = atol(argv[++i]);
+ break;
+ case 'A':
+ opt_auto_resize = 1;
+ break;
+ case 'B':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ mainret = 1;
+ goto end;
+ }
+ i++;
+ if (!strcmp("order", argv[i]))
+ memory_backend = &cds_lfht_mm_order;
+ else if (!strcmp("chunk", argv[i]))
+ memory_backend = &cds_lfht_mm_chunk;
+ else if (!strcmp("mmap", argv[i]))
+ memory_backend = &cds_lfht_mm_mmap;
+ else {
+ printf("Please specify memory backend with order|chunk|mmap.\n");
+ mainret = 1;
+ goto end;
+ }
+ break;
+ case 'R':
+ lookup_pool_offset = atol(argv[++i]);
+ break;
+ case 'S':
+ write_pool_offset = atol(argv[++i]);
+ break;
+ case 'T':
+ init_pool_offset = atol(argv[++i]);
+ break;
+ case 'M':
+ lookup_pool_size = atol(argv[++i]);
+ break;
+ case 'N':
+ write_pool_size = atol(argv[++i]);
+ break;
+ case 'O':
+ init_pool_size = atol(argv[++i]);
+ break;
+ case 'V':
+ validate_lookup = 1;
+ break;
+ case 'U':
+ test_choice = TEST_HASH_UNIQUE;
+ break;
+ case 'C':
+ nr_hash_chains = atol(argv[++i]);
+ break;
+ }
+ }
+
+ /* Check if hash size is power of 2 */
+ if (init_hash_size && init_hash_size & (init_hash_size - 1)) {
+ printf("Error: Initial number of buckets (%lu) is not a power of 2.\n",
+ init_hash_size);
+ mainret = 1;
+ goto end;
+ }
+
+ if (min_hash_alloc_size && min_hash_alloc_size & (min_hash_alloc_size - 1)) {
+ printf("Error: Minimum number of allocated buckets (%lu) is not a power of 2.\n",
+ min_hash_alloc_size);
+ mainret = 1;
+ goto end;
+ }
+
+ if (max_hash_buckets_size && max_hash_buckets_size & (max_hash_buckets_size - 1)) {
+ printf("Error: Maximum number of buckets (%lu) is not a power of 2.\n",
+ max_hash_buckets_size);
+ mainret = 1;
+ goto end;
+ }
+
+ memset(&act, 0, sizeof(act));
+ ret = sigemptyset(&act.sa_mask);
+ if (ret == -1) {
+ perror("sigemptyset");
+ mainret = 1;
+ goto end;
+ }
+ act.sa_handler = get_sigusr1_cb();
+ act.sa_flags = SA_RESTART;
+ ret = sigaction(SIGUSR1, &act, NULL);
+ if (ret == -1) {
+ perror("sigaction");
+ mainret = 1;
+ goto end;
+ }
+
+ act.sa_handler = get_sigusr2_cb();
+ act.sa_flags = SA_RESTART;
+ ret = sigaction(SIGUSR2, &act, NULL);
+ if (ret == -1) {
+ perror("sigaction");
+ mainret = 1;
+ goto end;
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("Mode:%s%s.\n",
+ add_only ? " add only" : " add/remove",
+ add_unique ? " uniquify" : ( add_replace ? " replace" : " insert"));
+ printf_verbose("Initial number of buckets: %lu buckets.\n", init_hash_size);
+ printf_verbose("Minimum number of allocated buckets: %lu buckets.\n", min_hash_alloc_size);
+ printf_verbose("Maximum number of buckets: %lu buckets.\n", max_hash_buckets_size);
+ printf_verbose("Init pool size offset %lu size %lu.\n",
+ init_pool_offset, init_pool_size);
+ printf_verbose("Lookup pool size offset %lu size %lu.\n",
+ lookup_pool_offset, lookup_pool_size);
+ printf_verbose("Update pool size offset %lu size %lu.\n",
+ write_pool_offset, write_pool_size);
+ printf_verbose("Number of hash chains: %lu.\n",
+ nr_hash_chains);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ if (!tid_reader) {
+ mainret = 1;
+ goto end;
+ }
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ if (!tid_writer) {
+ mainret = 1;
+ goto end_free_tid_reader;
+ }
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ if (!count_reader) {
+ mainret = 1;
+ goto end_free_tid_writer;
+ }
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+ if (!count_writer) {
+ mainret = 1;
+ goto end_free_count_reader;
+ }
+
+ err = create_all_cpu_call_rcu_data(0);
+ if (err) {
+ printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
+ }
+
+ if (memory_backend) {
+ test_ht = _cds_lfht_new(init_hash_size, min_hash_alloc_size,
+ max_hash_buckets_size,
+ (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
+ CDS_LFHT_ACCOUNTING, memory_backend,
+ &rcu_flavor, NULL);
+ } else {
+ test_ht = cds_lfht_new(init_hash_size, min_hash_alloc_size,
+ max_hash_buckets_size,
+ (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
+ CDS_LFHT_ACCOUNTING, NULL);
+ }
+ if (!test_ht) {
+ printf("Error allocating hash table.\n");
+ mainret = 1;
+ goto end_free_call_rcu_data;
+ }
+
+ /*
+ * Hash Population needs to be seen as a RCU reader
+ * thread from the point of view of resize.
+ */
+ rcu_register_thread();
+ ret = (get_populate_hash_cb())();
+ assert(!ret);
+
+ rcu_thread_offline();
+
+ next_aff = 0;
+
+ ret = pipe(count_pipe);
+ if (ret == -1) {
+ perror("pipe");
+ mainret = 1;
+ goto end_online;
+ }
+
+ /* spawn counter thread */
+ err = pthread_create(&tid_count, NULL, thr_count,
+ NULL);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_create");
+ goto end_close_pipe;
+ }
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i],
+ NULL, get_thr_reader_cb(),
+ &count_reader[i]);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_create");
+ goto end_pthread_join;
+ }
+ nr_readers_created++;
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i],
+ NULL, get_thr_writer_cb(),
+ &count_writer[i]);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_create");
+ goto end_pthread_join;
+ }
+ nr_writers_created++;
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ remain = duration;
+ do {
+ remain = sleep(remain);
+ } while (remain > 0);
+
+ test_stop = 1;
+
+end_pthread_join:
+ for (i = 0; i < nr_readers_created; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_join");
+ }
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers_created; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_join");
+ }
+ tot_writes += count_writer[i].update_ops;
+ tot_add += count_writer[i].add;
+ tot_add_exist += count_writer[i].add_exist;
+ tot_remove += count_writer[i].remove;
+ }
+
+ /* teardown counter thread */
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = SA_RESTART;
+ ret = sigaction(SIGUSR2, &act, NULL);
+ if (ret == -1) {
+ mainret = 1;
+ perror("sigaction");
+ }
+ {
+ char msg[1] = { 0x42 };
+ ssize_t ret;
+
+ do {
+ ret = write(count_pipe[1], msg, 1); /* wakeup thread */
+ } while (ret == -1L && errno == EINTR);
+ }
+ err = pthread_join(tid_count, &tret);
+ if (err != 0) {
+ errno = err;
+ mainret = 1;
+ perror("pthread_join");
+ }
+
+end_close_pipe:
+ for (i = 0; i < 2; i++) {
+ err = close(count_pipe[i]);
+ if (err) {
+ mainret = 1;
+ perror("close pipe");
+ }
+ }
+ fflush(stdout);
+end_online:
+ rcu_thread_online();
+ rcu_read_lock();
+ printf("Counting nodes... ");
+ cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
+ printf("done.\n");
+ test_delete_all_nodes(test_ht);
+ rcu_read_unlock();
+ rcu_thread_offline();
+ if (count) {
+ printf("Approximation before node accounting: %ld nodes.\n",
+ approx_before);
+ printf("Nodes deleted from hash table before destroy: "
+ "%lu nodes.\n",
+ count);
+ printf("Approximation after node accounting: %ld nodes.\n",
+ approx_after);
+ }
+
+ ret = cds_lfht_destroy(test_ht, NULL);
+ if (ret) {
+ printf_verbose("final delete aborted\n");
+ mainret = 1;
+ } else {
+ printf_verbose("final delete success\n");
+ }
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ nr_leaked = (long long) tot_add + init_populate - tot_remove - count;
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
+ "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
+ argv[0], duration, nr_readers, rduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
+ nr_leaked);
+ if (nr_leaked != 0) {
+ mainret = 1;
+ printf("WARNING: %lld nodes were leaked!\n", nr_leaked);
+ }
+
+ rcu_unregister_thread();
+end_free_call_rcu_data:
+ free_all_cpu_call_rcu_data();
+ free(count_writer);
+end_free_count_reader:
+ free(count_reader);
+end_free_tid_writer:
+ free(tid_writer);
+end_free_tid_reader:
+ free(tid_reader);
+end:
+ if (!mainret)
+ exit(EXIT_SUCCESS);
+ else
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+#ifndef _TEST_URCU_HASH_H
+#define _TEST_URCU_HASH_H
+
+/*
+ * test_urcu_hash.h
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+#define DEFAULT_HASH_SIZE 32
+#define DEFAULT_MIN_ALLOC_SIZE 1
+#define DEFAULT_RAND_POOL 1000000
+
+/*
+ * Note: the hash seed should be a random value for hash tables
+ * targeting production environments to provide protection against
+ * denial of service attacks. We keep it a static value within this test
+ * program to compare identical benchmark runs.
+ */
+#define TEST_HASH_SEED 0x42UL
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifdef POISON_FREE
+#define poison_free(ptr) \
+ do { \
+ memset(ptr, 0x42, sizeof(*(ptr))); \
+ free(ptr); \
+ } while (0)
+#else
+#define poison_free(ptr) free(ptr)
+#endif
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define debug_yield_read()
+#endif
+#include <urcu-qsbr.h>
+#include <urcu/rculfhash.h>
+#include <urcu-call-rcu.h>
+
+struct wr_count {
+ unsigned long update_ops;
+ unsigned long add;
+ unsigned long add_exist;
+ unsigned long remove;
+};
+
+extern DECLARE_URCU_TLS(unsigned int, rand_lookup);
+extern DECLARE_URCU_TLS(unsigned long, nr_add);
+extern DECLARE_URCU_TLS(unsigned long, nr_addexist);
+extern DECLARE_URCU_TLS(unsigned long, nr_del);
+extern DECLARE_URCU_TLS(unsigned long, nr_delnoent);
+extern DECLARE_URCU_TLS(unsigned long, lookup_fail);
+extern DECLARE_URCU_TLS(unsigned long, lookup_ok);
+
+extern struct cds_lfht *test_ht;
+
+struct test_data {
+ int a;
+ int b;
+};
+
+struct lfht_test_node {
+ struct cds_lfht_node node;
+ void *key;
+ unsigned int key_len;
+ /* cache-cold for iteration */
+ struct rcu_head head;
+};
+
+static inline struct lfht_test_node *
+to_test_node(struct cds_lfht_node *node)
+{
+ return caa_container_of(node, struct lfht_test_node, node);
+}
+
+static inline
+void lfht_test_node_init(struct lfht_test_node *node, void *key,
+ size_t key_len)
+{
+ cds_lfht_node_init(&node->node);
+ node->key = key;
+ node->key_len = key_len;
+}
+
+static inline struct lfht_test_node *
+cds_lfht_iter_get_test_node(struct cds_lfht_iter *iter)
+{
+ return to_test_node(cds_lfht_iter_get_node(iter));
+}
+
+extern volatile int test_go, test_stop;
+
+extern unsigned long wdelay;
+
+extern unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+extern unsigned long rduration;
+
+extern unsigned long init_hash_size;
+extern unsigned long min_hash_alloc_size;
+extern unsigned long max_hash_buckets_size;
+extern unsigned long init_populate;
+extern int opt_auto_resize;
+extern int add_only, add_unique, add_replace;
+extern const struct cds_lfht_mm_type *memory_backend;
+
+extern unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
+extern unsigned long init_pool_size,
+ lookup_pool_size,
+ write_pool_size;
+extern int validate_lookup;
+
+extern unsigned long nr_hash_chains;
+
+extern int count_pipe[2];
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+extern int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, ## args); \
+ } while (0)
+
+extern unsigned int cpu_affinities[NR_CPUS];
+extern unsigned int next_aff;
+extern int use_affinity;
+
+extern pthread_mutex_t affinity_mutex;
+
+void set_affinity(void);
+
+/*
+ * returns 0 if test should end.
+ */
+static inline int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static inline int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+extern DECLARE_URCU_TLS(unsigned long long, nr_writes);
+extern DECLARE_URCU_TLS(unsigned long long, nr_reads);
+
+extern unsigned int nr_readers;
+extern unsigned int nr_writers;
+
+void rcu_copy_mutex_lock(void);
+void rcu_copy_mutex_unlock(void);
+
+/*
+ * Hash function
+ * Source: http://burtleburtle.net/bob/c/lookup3.c
+ * Originally Public Domain
+ */
+
+#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
+
+#define mix(a, b, c) \
+do { \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c, 16); c += b; \
+ b -= a; b ^= rot(a, 19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+} while (0)
+
+#define final(a, b, c) \
+{ \
+ c ^= b; c -= rot(b, 14); \
+ a ^= c; a -= rot(c, 11); \
+ b ^= a; b -= rot(a, 25); \
+ c ^= b; c -= rot(b, 16); \
+ a ^= c; a -= rot(c, 4);\
+ b ^= a; b -= rot(a, 14); \
+ c ^= b; c -= rot(b, 24); \
+}
+
+static inline __attribute__((unused))
+uint32_t hash_u32(
+ const uint32_t *k, /* the key, an array of uint32_t values */
+ size_t length, /* the length of the key, in uint32_ts */
+ uint32_t initval) /* the previous hash, or an arbitrary value */
+{
+ uint32_t a, b, c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
+
+ /*----------------------------------------- handle most of the key */
+ while (length > 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a, b, c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*----------------------------------- handle the last 3 uint32_t's */
+ switch (length) { /* all the case statements fall through */
+ case 3: c += k[2];
+ case 2: b += k[1];
+ case 1: a += k[0];
+ final(a, b, c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*---------------------------------------------- report the result */
+ return c;
+}
+
+static inline
+void hashword2(
+ const uint32_t *k, /* the key, an array of uint32_t values */
+ size_t length, /* the length of the key, in uint32_ts */
+ uint32_t *pc, /* IN: seed OUT: primary hash value */
+ uint32_t *pb) /* IN: more seed OUT: secondary hash value */
+{
+ uint32_t a, b, c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
+ c += *pb;
+
+ /*----------------------------------------- handle most of the key */
+ while (length > 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a, b, c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*----------------------------------- handle the last 3 uint32_t's */
+ switch (length) { /* all the case statements fall through */
+ case 3: c += k[2];
+ case 2: b += k[1];
+ case 1: a += k[0];
+ final(a, b, c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*---------------------------------------------- report the result */
+ *pc = c;
+ *pb = b;
+}
+
+#if (CAA_BITS_PER_LONG == 32)
+static inline
+unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
+{
+ unsigned int key = (unsigned int) _key;
+
+ assert(length == sizeof(unsigned int));
+ return hash_u32(&key, 1, seed);
+}
+#else
+static inline
+unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
+{
+ union {
+ uint64_t v64;
+ uint32_t v32[2];
+ } v;
+ union {
+ uint64_t v64;
+ uint32_t v32[2];
+ } key;
+
+ assert(length == sizeof(unsigned long));
+ v.v64 = (uint64_t) seed;
+ key.v64 = (uint64_t) _key;
+ hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
+ return v.v64;
+}
+#endif
+
+/*
+ * Hash function with nr_hash_chains != 0 for testing purpose only!
+ * Creates very long hash chains, deteriorating the hash table into a
+ * few linked lists, depending on the nr_hash_chains value. The purpose
+ * of this test is to check how the hash table behaves with hash chains
+ * containing different values, which is a rare case in a normal hash
+ * table.
+ */
+static inline
+unsigned long test_hash(const void *_key, size_t length,
+ unsigned long seed)
+{
+ if (nr_hash_chains == 0) {
+ return test_hash_mix(_key, length, seed);
+ } else {
+ unsigned long v;
+
+ assert(length == sizeof(unsigned long));
+ v = (unsigned long) _key;
+ return v % nr_hash_chains;
+ }
+}
+
+unsigned long test_compare(const void *key1, size_t key1_len,
+ const void *key2, size_t key2_len);
+
+static inline
+int test_match(struct cds_lfht_node *node, const void *key)
+{
+ struct lfht_test_node *test_node = to_test_node(node);
+
+ return !test_compare(test_node->key, test_node->key_len,
+ key, sizeof(unsigned long));
+}
+
+static inline
+void cds_lfht_test_lookup(struct cds_lfht *ht, void *key, size_t key_len,
+ struct cds_lfht_iter *iter)
+{
+ assert(key_len == sizeof(unsigned long));
+
+ cds_lfht_lookup(ht, test_hash(key, key_len, TEST_HASH_SEED),
+ test_match, key, iter);
+}
+
+void free_node_cb(struct rcu_head *head);
+
+/* rw test */
+void test_hash_rw_sigusr1_handler(int signo);
+void test_hash_rw_sigusr2_handler(int signo);
+void *test_hash_rw_thr_reader(void *_count);
+void *test_hash_rw_thr_writer(void *_count);
+int test_hash_rw_populate_hash(void);
+
+/* unique test */
+void test_hash_unique_sigusr1_handler(int signo);
+void test_hash_unique_sigusr2_handler(int signo);
+void *test_hash_unique_thr_reader(void *_count);
+void *test_hash_unique_thr_writer(void *_count);
+int test_hash_unique_populate_hash(void);
+
+#endif /* _TEST_URCU_HASH_H */
--- /dev/null
+/*
+ * test_urcu_hash_rw.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "test_urcu_hash.h"
+
+enum urcu_hash_addremove {
+ AR_RANDOM = 0,
+ AR_ADD = 1,
+ AR_REMOVE = -1,
+}; /* 1: add, -1 remove, 0: random */
+
+static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */
+
+void test_hash_rw_sigusr1_handler(int signo)
+{
+ switch (addremove) {
+ case AR_ADD:
+ printf("Add/Remove: random.\n");
+ addremove = AR_RANDOM;
+ break;
+ case AR_RANDOM:
+ printf("Add/Remove: remove only.\n");
+ addremove = AR_REMOVE;
+ break;
+ case AR_REMOVE:
+ printf("Add/Remove: add only.\n");
+ addremove = AR_ADD;
+ break;
+ }
+}
+
+void test_hash_rw_sigusr2_handler(int signo)
+{
+ char msg[1] = { 0x42 };
+ ssize_t ret;
+
+ do {
+ ret = write(count_pipe[1], msg, 1); /* wakeup thread */
+ } while (ret == -1L && errno == EINTR);
+}
+
+void *test_hash_rw_thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct lfht_test_node *node;
+ struct cds_lfht_iter iter;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ cds_lfht_test_lookup(test_ht,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset),
+ sizeof(void *), &iter);
+ node = cds_lfht_iter_get_test_node(&iter);
+ if (node == NULL) {
+ if (validate_lookup) {
+ printf("[ERROR] Lookup cannot find initial node.\n");
+ exit(-1);
+ }
+ URCU_TLS(lookup_fail)++;
+ } else {
+ URCU_TLS(lookup_ok)++;
+ }
+ rcu_debug_yield_read();
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ printf_verbose("read tid : %lx, lookupfail %lu, lookupok %lu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(lookup_fail),
+ URCU_TLS(lookup_ok));
+ return ((void*)1);
+
+}
+
+void *test_hash_rw_thr_writer(void *_count)
+{
+ struct lfht_test_node *node;
+ struct cds_lfht_node *ret_node;
+ struct cds_lfht_iter iter;
+ struct wr_count *count = _count;
+ int ret;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ if ((addremove == AR_ADD || add_only)
+ || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
+ node = malloc(sizeof(struct lfht_test_node));
+ lfht_test_node_init(node,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
+ sizeof(void *));
+ rcu_read_lock();
+ if (add_unique) {
+ ret_node = cds_lfht_add_unique(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ } else {
+ if (add_replace)
+ ret_node = cds_lfht_add_replace(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ else
+ cds_lfht_add(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ &node->node);
+ }
+ rcu_read_unlock();
+ if (add_unique && ret_node != &node->node) {
+ free(node);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ if (add_replace && ret_node) {
+ call_rcu(&to_test_node(ret_node)->head,
+ free_node_cb);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ }
+ } else {
+ /* May delete */
+ rcu_read_lock();
+ cds_lfht_test_lookup(test_ht,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
+ sizeof(void *), &iter);
+ ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
+ rcu_read_unlock();
+ if (ret == 0) {
+ node = cds_lfht_iter_get_test_node(&iter);
+ call_rcu(&node->head, free_node_cb);
+ URCU_TLS(nr_del)++;
+ } else
+ URCU_TLS(nr_delnoent)++;
+ }
+#if 0
+ //if (URCU_TLS(nr_writes) % 100000 == 0) {
+ if (URCU_TLS(nr_writes) % 1000 == 0) {
+ rcu_read_lock();
+ if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
+ ht_resize(test_ht, 1);
+ } else {
+ ht_resize(test_ht, -1);
+ }
+ rcu_read_unlock();
+ }
+#endif //0
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+ "nr_delnoent %lu\n", urcu_get_thread_id(),
+ URCU_TLS(nr_add),
+ URCU_TLS(nr_addexist),
+ URCU_TLS(nr_del),
+ URCU_TLS(nr_delnoent));
+ count->update_ops = URCU_TLS(nr_writes);
+ count->add = URCU_TLS(nr_add);
+ count->add_exist = URCU_TLS(nr_addexist);
+ count->remove = URCU_TLS(nr_del);
+ return ((void*)2);
+}
+
+int test_hash_rw_populate_hash(void)
+{
+ struct lfht_test_node *node;
+ struct cds_lfht_node *ret_node;
+
+ if (!init_populate)
+ return 0;
+
+ printf("Starting rw test\n");
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ if ((add_unique || add_replace) && init_populate * 10 > init_pool_size) {
+ printf("WARNING: required to populate %lu nodes (-k), but random "
+"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
+"larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
+ }
+
+ while (URCU_TLS(nr_add) < init_populate) {
+ node = malloc(sizeof(struct lfht_test_node));
+ lfht_test_node_init(node,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
+ sizeof(void *));
+ rcu_read_lock();
+ if (add_unique) {
+ ret_node = cds_lfht_add_unique(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ } else {
+ if (add_replace)
+ ret_node = cds_lfht_add_replace(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ else
+ cds_lfht_add(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ &node->node);
+ }
+ rcu_read_unlock();
+ if (add_unique && ret_node != &node->node) {
+ free(node);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ if (add_replace && ret_node) {
+ call_rcu(&to_test_node(ret_node)->head, free_node_cb);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ }
+ URCU_TLS(nr_writes)++;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_hash_unique.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "test_urcu_hash.h"
+
+enum urcu_hash_addremove {
+ AR_RANDOM = 0,
+ AR_ADD = 1,
+ AR_REMOVE = -1,
+}; /* 1: add, -1 remove, 0: random */
+
+static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */
+
+void test_hash_unique_sigusr1_handler(int signo)
+{
+ switch (addremove) {
+ case AR_ADD:
+ printf("Add/Remove: random.\n");
+ addremove = AR_RANDOM;
+ break;
+ case AR_RANDOM:
+ printf("Add/Remove: remove only.\n");
+ addremove = AR_REMOVE;
+ break;
+ case AR_REMOVE:
+ printf("Add/Remove: add only.\n");
+ addremove = AR_ADD;
+ break;
+ }
+}
+
+void test_hash_unique_sigusr2_handler(int signo)
+{
+ char msg[1] = { 0x42 };
+ ssize_t ret;
+
+ do {
+ ret = write(count_pipe[1], msg, 1); /* wakeup thread */
+ } while (ret == -1L && errno == EINTR);
+}
+
+void *test_hash_unique_thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct lfht_test_node *node;
+ struct cds_lfht_iter iter;
+ /*
+ * iterate on whole table, ensuring that no duplicate is
+ * found.
+ */
+ rcu_read_lock();
+ cds_lfht_for_each_entry(test_ht, &iter, node, node) {
+ struct cds_lfht_iter dup_iter;
+
+ dup_iter = iter;
+ cds_lfht_next_duplicate(test_ht, test_match,
+ node->key, &dup_iter);
+ if (dup_iter.node != NULL) {
+ printf("[ERROR] Duplicate key %p found\n", node->key);
+ }
+ }
+ rcu_read_unlock();
+
+ rcu_debug_yield_read();
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ URCU_TLS(nr_reads)++;
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ printf_verbose("read tid : %lu, lookupfail %lu, lookupok %lu\n",
+ urcu_get_thread_id(), URCU_TLS(lookup_fail),
+ URCU_TLS(lookup_ok));
+ return ((void*)1);
+
+}
+
+void *test_hash_unique_thr_writer(void *_count)
+{
+ struct lfht_test_node *node;
+ struct cds_lfht_node *ret_node;
+ struct cds_lfht_iter iter;
+ struct wr_count *count = _count;
+ int ret;
+ int loc_add_unique;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ /*
+ * add unique/add replace with new node key from range.
+ */
+ if (1 || (addremove == AR_ADD || add_only)
+ || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
+ node = malloc(sizeof(struct lfht_test_node));
+ lfht_test_node_init(node,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
+ sizeof(void *));
+ rcu_read_lock();
+ loc_add_unique = rand_r(&URCU_TLS(rand_lookup)) & 1;
+ if (loc_add_unique) {
+ ret_node = cds_lfht_add_unique(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ } else {
+ ret_node = cds_lfht_add_replace(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+#if 0 //generate an error on purpose
+ cds_lfht_add(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ &node->node);
+ ret_node = NULL;
+#endif //0
+ }
+ rcu_read_unlock();
+ if (loc_add_unique) {
+ if (ret_node != &node->node) {
+ free(node);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ } else {
+ if (ret_node) {
+ call_rcu(&to_test_node(ret_node)->head,
+ free_node_cb);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ }
+ } else {
+ /* May delete */
+ rcu_read_lock();
+ cds_lfht_test_lookup(test_ht,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
+ sizeof(void *), &iter);
+ ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
+ rcu_read_unlock();
+ if (ret == 0) {
+ node = cds_lfht_iter_get_test_node(&iter);
+ call_rcu(&node->head, free_node_cb);
+ URCU_TLS(nr_del)++;
+ } else
+ URCU_TLS(nr_delnoent)++;
+ }
+#if 0
+ //if (URCU_TLS(nr_writes) % 100000 == 0) {
+ if (URCU_TLS(nr_writes) % 1000 == 0) {
+ rcu_read_lock();
+ if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
+ ht_resize(test_ht, 1);
+ } else {
+ ht_resize(test_ht, -1);
+ }
+ rcu_read_unlock();
+ }
+#endif //0
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ }
+
+ rcu_unregister_thread();
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+ "nr_delnoent %lu\n", urcu_get_thread_id(),
+ URCU_TLS(nr_add),
+ URCU_TLS(nr_addexist),
+ URCU_TLS(nr_del),
+ URCU_TLS(nr_delnoent));
+ count->update_ops = URCU_TLS(nr_writes);
+ count->add = URCU_TLS(nr_add);
+ count->add_exist = URCU_TLS(nr_addexist);
+ count->remove = URCU_TLS(nr_del);
+ return ((void*)2);
+}
+
+int test_hash_unique_populate_hash(void)
+{
+ struct lfht_test_node *node;
+ struct cds_lfht_node *ret_node;
+
+ printf("Starting uniqueness test.\n");
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
+
+ if (!init_populate)
+ return 0;
+
+ if (init_populate * 10 > init_pool_size) {
+ printf("WARNING: required to populate %lu nodes (-k), but random "
+"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
+"larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
+ }
+
+ while (URCU_TLS(nr_add) < init_populate) {
+ node = malloc(sizeof(struct lfht_test_node));
+ lfht_test_node_init(node,
+ (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
+ sizeof(void *));
+ rcu_read_lock();
+ ret_node = cds_lfht_add_replace(test_ht,
+ test_hash(node->key, node->key_len, TEST_HASH_SEED),
+ test_match, node->key, &node->node);
+ rcu_read_unlock();
+ if (ret_node) {
+ call_rcu(&to_test_node(ret_node)->head, free_node_cb);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ URCU_TLS(nr_writes)++;
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_lfq.c
+ *
+ * Userspace RCU library - example RCU-based lock-free queue
+ *
+ * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+#include <urcu.h>
+#include <urcu/cds.h>
+
+static volatile int test_go, test_stop;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+struct test {
+ struct cds_lfq_node_rcu list;
+ struct rcu_head rcu;
+};
+
+static struct cds_lfq_queue_rcu q;
+
+void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct test *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_lfq_node_init_rcu(&node->list);
+ rcu_read_lock();
+ cds_lfq_enqueue_rcu(&q, &node->list);
+ rcu_read_unlock();
+ URCU_TLS(nr_successful_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
+ return ((void*)1);
+
+}
+
+static
+void free_node_cb(struct rcu_head *head)
+{
+ struct test *node =
+ caa_container_of(head, struct test, rcu);
+ free(node);
+}
+
+void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_lfq_node_rcu *qnode;
+
+ rcu_read_lock();
+ qnode = cds_lfq_dequeue_rcu(&q);
+ rcu_read_unlock();
+
+ if (qnode) {
+ struct test *node;
+
+ node = caa_container_of(qnode, struct test, list);
+ call_rcu(&node->rcu, free_node_cb);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+
+ URCU_TLS(nr_dequeues)++;
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ rcu_unregister_thread();
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ return ((void*)2);
+}
+
+void test_end(struct cds_lfq_queue_rcu *q, unsigned long long *nr_dequeues)
+{
+ struct cds_lfq_node_rcu *snode;
+
+ do {
+ snode = cds_lfq_dequeue_rcu(q);
+ if (snode) {
+ struct test *node;
+
+ node = caa_container_of(snode, struct test, list);
+ free(node); /* no more concurrent access */
+ (*nr_dequeues)++;
+ }
+ } while (snode);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
+ cds_lfq_init_rcu(&q, call_rcu);
+ err = create_all_cpu_call_rcu_data(0);
+ if (err) {
+ printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
+ }
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[2 * i];
+ tot_successful_enqueues += count_enqueuer[2 * i + 1];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[2 * i];
+ tot_successful_dequeues += count_dequeuer[2 * i + 1];
+ }
+
+ test_end(&q, &end_dequeues);
+ err = cds_lfq_destroy_rcu(&q);
+ assert(!err);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "successful dequeues %llu\n",
+ tot_successful_enqueues, tot_successful_dequeues);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu successful dequeues %12llu "
+ "end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_successful_dequeues, end_dequeues,
+ tot_enqueues + tot_dequeues);
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+
+ free_all_cpu_call_rcu_data();
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_lfs.c
+ *
+ * Userspace RCU library - example lock-free stack
+ *
+ * Copyright 2010-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+#include <urcu.h>
+#include <urcu/cds.h>
+
+/*
+ * External synchronization used.
+ */
+enum test_sync {
+ TEST_SYNC_NONE = 0,
+ TEST_SYNC_RCU,
+};
+
+static enum test_sync test_sync;
+
+static volatile int test_go, test_stop;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+static int test_pop, test_pop_all;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, ## args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+struct test {
+ struct cds_lfs_node list;
+ struct rcu_head rcu;
+};
+
+static struct cds_lfs_stack s;
+
+static void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct test *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_lfs_node_init(&node->list);
+ cds_lfs_push(&s, &node->list);
+ URCU_TLS(nr_successful_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
+ return ((void*)1);
+
+}
+
+static
+void free_node_cb(struct rcu_head *head)
+{
+ struct test *node =
+ caa_container_of(head, struct test, rcu);
+ free(node);
+}
+
+static
+void do_test_pop(enum test_sync sync)
+{
+ struct cds_lfs_node *snode;
+
+ if (sync == TEST_SYNC_RCU)
+ rcu_read_lock();
+ snode = __cds_lfs_pop(&s);
+ if (sync == TEST_SYNC_RCU)
+ rcu_read_unlock();
+ if (snode) {
+ struct test *node;
+
+ node = caa_container_of(snode,
+ struct test, list);
+ if (sync == TEST_SYNC_RCU)
+ call_rcu(&node->rcu, free_node_cb);
+ else
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+ URCU_TLS(nr_dequeues)++;
+}
+
+static
+void do_test_pop_all(enum test_sync sync)
+{
+ struct cds_lfs_node *snode;
+ struct cds_lfs_head *head;
+ struct cds_lfs_node *n;
+
+ head = __cds_lfs_pop_all(&s);
+ cds_lfs_for_each_safe(head, snode, n) {
+ struct test *node;
+
+ node = caa_container_of(snode, struct test, list);
+ if (sync == TEST_SYNC_RCU)
+ call_rcu(&node->rcu, free_node_cb);
+ else
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ URCU_TLS(nr_dequeues)++;
+ }
+
+}
+
+static void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+ unsigned int counter = 0;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ assert(test_pop || test_pop_all);
+
+ for (;;) {
+ if (test_pop && test_pop_all) {
+ /* both pop and pop all */
+ if (counter & 1)
+ do_test_pop(test_sync);
+ else
+ do_test_pop_all(test_sync);
+ counter++;
+ } else {
+ if (test_pop)
+ do_test_pop(test_sync);
+ else
+ do_test_pop_all(test_sync);
+ }
+
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ rcu_unregister_thread();
+
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ return ((void*)2);
+}
+
+static void test_end(struct cds_lfs_stack *s, unsigned long long *nr_dequeues)
+{
+ struct cds_lfs_node *snode;
+
+ do {
+ snode = __cds_lfs_pop(s);
+ if (snode) {
+ struct test *node;
+
+ node = caa_container_of(snode, struct test, list);
+ free(node);
+ (*nr_dequeues)++;
+ }
+ } while (snode);
+}
+
+static void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf(" [-p] (test pop)\n");
+ printf(" [-P] (test pop_all, enabled by default)\n");
+ printf(" [-R] (use RCU external synchronization)\n");
+ printf(" Note: default: no external synchronization used.\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ case 'p':
+ test_pop = 1;
+ break;
+ case 'P':
+ test_pop_all = 1;
+ break;
+ case 'R':
+ test_sync = TEST_SYNC_RCU;
+ break;
+ }
+ }
+
+ /* activate pop_all test by default */
+ if (!test_pop && !test_pop_all)
+ test_pop_all = 1;
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ if (test_pop)
+ printf_verbose("pop test activated.\n");
+ if (test_pop_all)
+ printf_verbose("pop_all test activated.\n");
+ if (test_sync == TEST_SYNC_RCU)
+ printf_verbose("External sync: RCU.\n");
+ else
+ printf_verbose("External sync: none.\n");
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
+ cds_lfs_init(&s);
+ err = create_all_cpu_call_rcu_data(0);
+ if (err) {
+ printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
+ }
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[2 * i];
+ tot_successful_enqueues += count_enqueuer[2 * i + 1];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[2 * i];
+ tot_successful_dequeues += count_dequeuer[2 * i + 1];
+ }
+
+ test_end(&s, &end_dequeues);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "successful dequeues %llu\n",
+ tot_successful_enqueues, tot_successful_dequeues);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu successful dequeues %12llu "
+ "end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_successful_dequeues, end_dequeues,
+ tot_enqueues + tot_dequeues);
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+
+ free_all_cpu_call_rcu_data();
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_lfs_rcu.c
+ *
+ * Userspace RCU library - example RCU-based lock-free stack
+ *
+ * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+#include <urcu.h>
+
+/* Remove deprecation warnings from test build. */
+#define CDS_LFS_RCU_DEPRECATED
+
+#include <urcu/cds.h>
+
+static volatile int test_go, test_stop;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+ cpu_set_t mask;
+ int cpu;
+ int ret;
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+struct test {
+ struct cds_lfs_node_rcu list;
+ struct rcu_head rcu;
+};
+
+static struct cds_lfs_stack_rcu s;
+
+void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct test *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_lfs_node_init_rcu(&node->list);
+ /* No rcu read-side is needed for push */
+ cds_lfs_push_rcu(&s, &node->list);
+ URCU_TLS(nr_successful_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
+ return ((void*)1);
+
+}
+
+static
+void free_node_cb(struct rcu_head *head)
+{
+ struct test *node =
+ caa_container_of(head, struct test, rcu);
+ free(node);
+}
+
+void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_lfs_node_rcu *snode;
+
+ rcu_read_lock();
+ snode = cds_lfs_pop_rcu(&s);
+ rcu_read_unlock();
+ if (snode) {
+ struct test *node;
+
+ node = caa_container_of(snode, struct test, list);
+ call_rcu(&node->rcu, free_node_cb);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+ URCU_TLS(nr_dequeues)++;
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ rcu_unregister_thread();
+
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ return ((void*)2);
+}
+
+void test_end(struct cds_lfs_stack_rcu *s, unsigned long long *nr_dequeues)
+{
+ struct cds_lfs_node_rcu *snode;
+
+ do {
+ snode = cds_lfs_pop_rcu(s);
+ if (snode) {
+ struct test *node;
+
+ node = caa_container_of(snode, struct test, list);
+ free(node);
+ (*nr_dequeues)++;
+ }
+ } while (snode);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
+ cds_lfs_init_rcu(&s);
+ err = create_all_cpu_call_rcu_data(0);
+ if (err) {
+ printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
+ }
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[2 * i];
+ tot_successful_enqueues += count_enqueuer[2 * i + 1];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[2 * i];
+ tot_successful_dequeues += count_dequeuer[2 * i + 1];
+ }
+
+ test_end(&s, &end_dequeues);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "successful dequeues %llu\n",
+ tot_successful_enqueues, tot_successful_dequeues);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu successful dequeues %12llu "
+ "end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_successful_dequeues, end_dequeues,
+ tot_enqueues + tot_dequeues);
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+
+ free_all_cpu_call_rcu_data();
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include "urcu-qsbr.h"
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static int *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ int *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ assert(rcu_read_ongoing());
+ rcu_thread_offline();
+ assert(!rcu_read_ongoing());
+ rcu_thread_online();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ rcu_read_lock();
+ assert(rcu_read_ongoing());
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(*local_ptr == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ /* QS each 1024 reads */
+ if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+ rcu_quiescent_state();
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ /* test extra thread registration */
+ rcu_register_thread();
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *_count)
+{
+ unsigned long long *count = _count;
+ int *new, *old;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ new = malloc(sizeof(int));
+ assert(new);
+ *new = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ synchronize_rcu();
+ if (old)
+ *old = 0;
+ free(old);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ *count = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader, *count_writer;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ count_writer = calloc(nr_writers, sizeof(*count_writer));
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ &count_writer[i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += count_writer[i];
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes);
+ free(test_rcu_pointer);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(count_writer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_gc.c
+ *
+ * Userspace RCU library - test program (with baatch reclamation)
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#define _LGPL_SOURCE
+#include <urcu-qsbr.h>
+
+struct test_array {
+ int a;
+};
+
+static volatile int test_go, test_stop;
+
+static unsigned long wdelay;
+
+static struct test_array *test_rcu_pointer;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long rduration;
+static unsigned int reclaim_batch = 1;
+
+struct reclaim_queue {
+ void **queue; /* Beginning of queue */
+ void **head; /* Insert position */
+};
+
+static struct reclaim_queue *pending_reclaims;
+
+
+/* write-side C.S. duration, in loops */
+static unsigned long wduration;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_write(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_read(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_writes);
+static DEFINE_URCU_TLS(unsigned long long, nr_reads);
+
+static unsigned int nr_readers;
+static unsigned int nr_writers;
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+static
+unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
+
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+void *thr_reader(void *_count)
+{
+ unsigned long long *count = _count;
+ struct test_array *local_ptr;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ set_affinity();
+
+ rcu_register_thread();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ _rcu_read_lock();
+ local_ptr = _rcu_dereference(test_rcu_pointer);
+ rcu_debug_yield_read();
+ if (local_ptr)
+ assert(local_ptr->a == 8);
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ _rcu_read_unlock();
+ URCU_TLS(nr_reads)++;
+ /* QS each 1024 reads */
+ if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+ _rcu_quiescent_state();
+ if (caa_unlikely(!test_duration_read()))
+ break;
+ }
+
+ rcu_unregister_thread();
+
+ *count = URCU_TLS(nr_reads);
+ printf_verbose("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+static void rcu_gc_clear_queue(unsigned long wtidx)
+{
+ void **p;
+
+ /* Wait for Q.S and empty queue */
+ synchronize_rcu();
+
+ for (p = pending_reclaims[wtidx].queue;
+ p < pending_reclaims[wtidx].head; p++) {
+ /* poison */
+ if (*p)
+ ((struct test_array *)*p)->a = 0;
+ free(*p);
+ }
+ pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue;
+}
+
+/* Using per-thread queue */
+static void rcu_gc_reclaim(unsigned long wtidx, void *old)
+{
+ /* Queue pointer */
+ *pending_reclaims[wtidx].head = old;
+ pending_reclaims[wtidx].head++;
+
+ if (caa_likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue
+ < reclaim_batch))
+ return;
+
+ rcu_gc_clear_queue(wtidx);
+}
+
+void *thr_writer(void *data)
+{
+ unsigned long wtidx = (unsigned long)data;
+#ifdef TEST_LOCAL_GC
+ struct test_array *old = NULL;
+#else
+ struct test_array *new, *old;
+#endif
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+#ifndef TEST_LOCAL_GC
+ new = malloc(sizeof(*new));
+ new->a = 8;
+ old = _rcu_xchg_pointer(&test_rcu_pointer, new);
+#endif
+ if (caa_unlikely(wduration))
+ loop_sleep(wduration);
+ rcu_gc_reclaim(wtidx, old);
+ URCU_TLS(nr_writes)++;
+ if (caa_unlikely(!test_duration_write()))
+ break;
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+ }
+
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
+ return ((void*)2);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+#ifdef DEBUG_YIELD
+ printf(" [-r] [-w] (yield reader and/or writer)\n");
+#endif
+ printf(" [-b batch] (batch reclaim)\n");
+ printf(" [-d delay] (writer period (us))\n");
+ printf(" [-c duration] (reader C.S. duration (in loops))\n");
+ printf(" [-e duration] (writer C.S. duration (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ unsigned long long *count_reader;
+ unsigned long long tot_reads = 0, tot_writes = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_readers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_writers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
+ case 'r':
+ rcu_yield_active |= RCU_YIELD_READ;
+ break;
+ case 'w':
+ rcu_yield_active |= RCU_YIELD_WRITE;
+ break;
+#endif
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'b':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ reclaim_batch = atol(argv[++i]);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'e':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wduration = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
+ duration, nr_readers, nr_writers);
+ printf_verbose("Writer delay : %lu loops.\n", wdelay);
+ printf_verbose("Reader duration : %lu loops.\n", rduration);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_reader = calloc(nr_readers, sizeof(*tid_reader));
+ tid_writer = calloc(nr_writers, sizeof(*tid_writer));
+ count_reader = calloc(nr_readers, sizeof(*count_reader));
+ tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
+ pending_reclaims = calloc(nr_writers, sizeof(*pending_reclaims));
+ if (reclaim_batch * sizeof(*pending_reclaims[i].queue)
+ < CAA_CACHE_LINE_SIZE)
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].queue = calloc(1, CAA_CACHE_LINE_SIZE);
+ else
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].queue = calloc(reclaim_batch,
+ sizeof(*pending_reclaims[i].queue));
+ for (i = 0; i < nr_writers; i++)
+ pending_reclaims[i].head = pending_reclaims[i].queue;
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ &count_reader[i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ sleep(duration);
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_readers; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_reads += count_reader[i];
+ }
+ for (i = 0; i < nr_writers; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_writes += tot_nr_writes[i];
+ rcu_gc_clear_queue(i);
+ }
+
+ printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
+ tot_writes);
+ printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
+ "nr_writers %3u "
+ "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
+ "batch %u\n",
+ argv[0], duration, nr_readers, rduration, wduration,
+ nr_writers, wdelay, tot_reads, tot_writes,
+ tot_reads + tot_writes, reclaim_batch);
+ free(tid_reader);
+ free(tid_writer);
+ free(count_reader);
+ free(tot_nr_writes);
+ for (i = 0; i < nr_writers; i++)
+ free(pending_reclaims[i].queue);
+ free(pending_reclaims);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_qsbr_timing.c
+ *
+ * Userspace QSBR - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include "thread-id.h"
+
+#define _LGPL_SOURCE
+#include <urcu-qsbr.h>
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+struct test_array {
+ int a;
+};
+
+static struct test_array *test_rcu_pointer;
+
+#define OUTER_READ_LOOP 2000U
+#define INNER_READ_LOOP 100000U
+#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
+
+#define OUTER_WRITE_LOOP 10U
+#define INNER_WRITE_LOOP 200U
+#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
+
+static int num_read;
+static int num_write;
+
+#define NR_READ num_read
+#define NR_WRITE num_write
+
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
+
+void *thr_reader(void *arg)
+{
+ int i, j;
+ struct test_array *local_ptr;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ sleep(2);
+
+ rcu_register_thread();
+
+ time1 = caa_get_cycles();
+ for (i = 0; i < OUTER_READ_LOOP; i++) {
+ for (j = 0; j < INNER_READ_LOOP; j++) {
+ _rcu_read_lock();
+ local_ptr = _rcu_dereference(test_rcu_pointer);
+ if (local_ptr) {
+ assert(local_ptr->a == 8);
+ }
+ _rcu_read_unlock();
+ }
+ _rcu_quiescent_state();
+ }
+ time2 = caa_get_cycles();
+
+ rcu_unregister_thread();
+
+ reader_time[(unsigned long)arg] = time2 - time1;
+
+ sleep(2);
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *arg)
+{
+ int i, j;
+ struct test_array *new, *old;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ sleep(2);
+
+ for (i = 0; i < OUTER_WRITE_LOOP; i++) {
+ for (j = 0; j < INNER_WRITE_LOOP; j++) {
+ time1 = caa_get_cycles();
+ new = malloc(sizeof(struct test_array));
+ rcu_copy_mutex_lock();
+ old = test_rcu_pointer;
+ if (old) {
+ assert(old->a == 8);
+ }
+ new->a = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ rcu_copy_mutex_unlock();
+ synchronize_rcu();
+ /* can be done after unlock */
+ if (old) {
+ old->a = 0;
+ }
+ free(old);
+ time2 = caa_get_cycles();
+ writer_time[(unsigned long)arg] += time2 - time1;
+ usleep(1);
+ }
+ }
+
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ return ((void*)2);
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ int i;
+ cycles_t tot_rtime = 0;
+ cycles_t tot_wtime = 0;
+
+ if (argc < 2) {
+ printf("Usage : %s nr_readers nr_writers\n", argv[0]);
+ exit(-1);
+ }
+ num_read = atoi(argv[1]);
+ num_write = atoi(argv[2]);
+
+ reader_time = calloc(num_read, sizeof(*reader_time));
+ writer_time = calloc(num_write, sizeof(*writer_time));
+ tid_reader = calloc(num_read, sizeof(*tid_reader));
+ tid_writer = calloc(num_write, sizeof(*tid_writer));
+
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ sleep(10);
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_rtime += reader_time[i];
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_wtime += writer_time[i];
+ }
+ free(test_rcu_pointer);
+ printf("Time per read : %g cycles\n",
+ (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
+ printf("Time per write : %g cycles\n",
+ (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
+
+ free(reader_time);
+ free(writer_time);
+ free(tid_reader);
+ free(tid_writer);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu.c
+ *
+ * Userspace RCU library - test program
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <urcu/arch.h>
+
+#include "thread-id.h"
+
+#define _LGPL_SOURCE
+#include <urcu.h>
+
+pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void rcu_copy_mutex_lock(void)
+{
+ int ret;
+ ret = pthread_mutex_lock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+}
+
+void rcu_copy_mutex_unlock(void)
+{
+ int ret;
+
+ ret = pthread_mutex_unlock(&rcu_copy_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+}
+
+struct test_array {
+ int a;
+};
+
+static struct test_array *test_rcu_pointer;
+
+#define OUTER_READ_LOOP 2000U
+#define INNER_READ_LOOP 100000U
+#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
+
+#define OUTER_WRITE_LOOP 10U
+#define INNER_WRITE_LOOP 200U
+#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
+
+static int num_read;
+static int num_write;
+
+#define NR_READ num_read
+#define NR_WRITE num_write
+
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
+static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
+
+void *thr_reader(void *arg)
+{
+ int i, j;
+ struct test_array *local_ptr;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ sleep(2);
+
+ rcu_register_thread();
+
+ time1 = caa_get_cycles();
+ for (i = 0; i < OUTER_READ_LOOP; i++) {
+ for (j = 0; j < INNER_READ_LOOP; j++) {
+ rcu_read_lock();
+ local_ptr = rcu_dereference(test_rcu_pointer);
+ if (local_ptr) {
+ assert(local_ptr->a == 8);
+ }
+ rcu_read_unlock();
+ }
+ }
+ time2 = caa_get_cycles();
+
+ rcu_unregister_thread();
+
+ reader_time[(unsigned long)arg] = time2 - time1;
+
+ sleep(2);
+ printf("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+ return ((void*)1);
+
+}
+
+void *thr_writer(void *arg)
+{
+ int i, j;
+ struct test_array *new, *old;
+ cycles_t time1, time2;
+
+ printf("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ sleep(2);
+
+ for (i = 0; i < OUTER_WRITE_LOOP; i++) {
+ for (j = 0; j < INNER_WRITE_LOOP; j++) {
+ time1 = caa_get_cycles();
+ new = malloc(sizeof(struct test_array));
+ rcu_copy_mutex_lock();
+ old = test_rcu_pointer;
+ if (old) {
+ assert(old->a == 8);
+ }
+ new->a = 8;
+ old = rcu_xchg_pointer(&test_rcu_pointer, new);
+ rcu_copy_mutex_unlock();
+ synchronize_rcu();
+ /* can be done after unlock */
+ if (old) {
+ old->a = 0;
+ }
+ free(old);
+ time2 = caa_get_cycles();
+ writer_time[(unsigned long)arg] += time2 - time1;
+ usleep(1);
+ }
+ }
+
+ printf("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+ return ((void*)2);
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_reader, *tid_writer;
+ void *tret;
+ int i;
+ cycles_t tot_rtime = 0;
+ cycles_t tot_wtime = 0;
+
+ if (argc < 2) {
+ printf("Usage : %s nr_readers nr_writers\n", argv[0]);
+ exit(-1);
+ }
+ num_read = atoi(argv[1]);
+ num_write = atoi(argv[2]);
+
+ reader_time = calloc(num_read, sizeof(*reader_time));
+ writer_time = calloc(num_write, sizeof(*writer_time));
+ tid_reader = calloc(num_read, sizeof(*tid_reader));
+ tid_writer = calloc(num_write, sizeof(*tid_writer));
+
+ printf("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_create(&tid_reader[i], NULL, thr_reader,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_create(&tid_writer[i], NULL, thr_writer,
+ (void *)(long)i);
+ if (err != 0)
+ exit(1);
+ }
+
+ sleep(10);
+
+ for (i = 0; i < NR_READ; i++) {
+ err = pthread_join(tid_reader[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_rtime += reader_time[i];
+ }
+ for (i = 0; i < NR_WRITE; i++) {
+ err = pthread_join(tid_writer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_wtime += writer_time[i];
+ }
+ free(test_rcu_pointer);
+ printf("Time per read : %g cycles\n",
+ (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
+ printf("Time per write : %g cycles\n",
+ (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
+
+ free(reader_time);
+ free(writer_time);
+ free(tid_reader);
+ free(tid_writer);
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_wfcq.c
+ *
+ * Userspace RCU library - example RCU-based lock-free concurrent queue
+ *
+ * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include <urcu/uatomic.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+#include <urcu/wfcqueue.h>
+
+enum test_sync {
+ TEST_SYNC_NONE = 0,
+ TEST_SYNC_MUTEX,
+};
+
+static enum test_sync test_sync;
+
+static int test_force_sync;
+
+static volatile int test_go, test_stop_enqueue, test_stop_dequeue;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+static int test_dequeue, test_splice, test_wait_empty;
+static int test_enqueue_stopped;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, ## args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop_dequeue;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop_enqueue;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+static DEFINE_URCU_TLS(unsigned long long, nr_empty_dest_enqueues);
+static DEFINE_URCU_TLS(unsigned long long, nr_splice);
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeue_last);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+static struct cds_wfcq_head __attribute__((aligned(CAA_CACHE_LINE_SIZE))) head;
+static struct cds_wfcq_tail __attribute__((aligned(CAA_CACHE_LINE_SIZE))) tail;
+
+static void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+ bool was_nonempty;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_wfcq_node *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_wfcq_node_init(node);
+ was_nonempty = cds_wfcq_enqueue(&head, &tail, node);
+ URCU_TLS(nr_successful_enqueues)++;
+ if (!was_nonempty)
+ URCU_TLS(nr_empty_dest_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ uatomic_inc(&test_enqueue_stopped);
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ count[2] = URCU_TLS(nr_empty_dest_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu, "
+ "empty_dest_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues),
+ URCU_TLS(nr_empty_dest_enqueues));
+ return ((void*)1);
+
+}
+
+static void do_test_dequeue(enum test_sync sync)
+{
+ struct cds_wfcq_node *node;
+ int state;
+
+ if (sync == TEST_SYNC_MUTEX)
+ node = cds_wfcq_dequeue_with_state_blocking(&head, &tail,
+ &state);
+ else
+ node = __cds_wfcq_dequeue_with_state_blocking(&head, &tail,
+ &state);
+
+ if (state & CDS_WFCQ_STATE_LAST)
+ URCU_TLS(nr_dequeue_last)++;
+
+ if (node) {
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+ URCU_TLS(nr_dequeues)++;
+}
+
+static void do_test_splice(enum test_sync sync)
+{
+ struct cds_wfcq_head tmp_head;
+ struct cds_wfcq_tail tmp_tail;
+ struct cds_wfcq_node *node, *n;
+ enum cds_wfcq_ret ret;
+
+ cds_wfcq_init(&tmp_head, &tmp_tail);
+
+ if (sync == TEST_SYNC_MUTEX)
+ ret = cds_wfcq_splice_blocking(&tmp_head, &tmp_tail,
+ &head, &tail);
+ else
+ ret = __cds_wfcq_splice_blocking(&tmp_head, &tmp_tail,
+ &head, &tail);
+
+ switch (ret) {
+ case CDS_WFCQ_RET_WOULDBLOCK:
+ assert(0); /* blocking call */
+ break;
+ case CDS_WFCQ_RET_DEST_EMPTY:
+ URCU_TLS(nr_splice)++;
+ URCU_TLS(nr_dequeue_last)++;
+ /* ok */
+ break;
+ case CDS_WFCQ_RET_DEST_NON_EMPTY:
+ assert(0); /* entirely unexpected */
+ break;
+ case CDS_WFCQ_RET_SRC_EMPTY:
+ /* ok, we could even skip iteration on dest if we wanted */
+ break;
+ }
+
+ __cds_wfcq_for_each_blocking_safe(&tmp_head, &tmp_tail, node, n) {
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ URCU_TLS(nr_dequeues)++;
+ }
+}
+
+static void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+ unsigned int counter = 0;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ if (test_dequeue && test_splice) {
+ if (counter & 1)
+ do_test_dequeue(test_sync);
+ else
+ do_test_splice(test_sync);
+ counter++;
+ } else {
+ if (test_dequeue)
+ do_test_dequeue(test_sync);
+ else
+ do_test_splice(test_sync);
+ }
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu, "
+ "nr_splice %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
+ URCU_TLS(nr_splice));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ count[2] = URCU_TLS(nr_splice);
+ count[3] = URCU_TLS(nr_dequeue_last);
+ return ((void*)2);
+}
+
+static void test_end(unsigned long long *nr_dequeues,
+ unsigned long long *nr_dequeue_last)
+{
+ struct cds_wfcq_node *node;
+ int state;
+
+ do {
+ node = cds_wfcq_dequeue_with_state_blocking(&head, &tail,
+ &state);
+ if (node) {
+ if (state & CDS_WFCQ_STATE_LAST)
+ (*nr_dequeue_last)++;
+ free(node);
+ (*nr_dequeues)++;
+ }
+ } while (node);
+}
+
+static void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf(" [-q] (test dequeue)\n");
+ printf(" [-s] (test splice, enabled by default)\n");
+ printf(" [-M] (use mutex external synchronization)\n");
+ printf(" Note: default: no external synchronization used.\n");
+ printf(" [-f] (force user-provided synchronization)\n");
+ printf(" [-w] Wait for dequeuer to empty queue\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0,
+ tot_empty_dest_enqueues = 0,
+ tot_splice = 0, tot_dequeue_last = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a, retval = 0;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ case 'q':
+ test_dequeue = 1;
+ break;
+ case 's':
+ test_splice = 1;
+ break;
+ case 'M':
+ test_sync = TEST_SYNC_MUTEX;
+ break;
+ case 'w':
+ test_wait_empty = 1;
+ break;
+ case 'f':
+ test_force_sync = 1;
+ break;
+ }
+ }
+
+ /* activate splice test by default */
+ if (!test_dequeue && !test_splice)
+ test_splice = 1;
+
+ if (test_sync == TEST_SYNC_NONE && nr_dequeuers > 1 && test_dequeue) {
+ if (test_force_sync) {
+ fprintf(stderr, "[WARNING] Using dequeue concurrently "
+ "with other dequeue or splice without external "
+ "synchronization. Expect run-time failure.\n");
+ } else {
+ printf("Enforcing mutex synchronization\n");
+ test_sync = TEST_SYNC_MUTEX;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ if (test_dequeue)
+ printf_verbose("dequeue test activated.\n");
+ else
+ printf_verbose("splice test activated.\n");
+ if (test_sync == TEST_SYNC_MUTEX)
+ printf_verbose("External sync: mutex.\n");
+ else
+ printf_verbose("External sync: none.\n");
+ if (test_wait_empty)
+ printf_verbose("Wait for dequeuers to empty queue.\n");
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 3 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 4 * sizeof(*count_dequeuer));
+ cds_wfcq_init(&head, &tail);
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[3 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[4 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop_enqueue = 1;
+
+ if (test_wait_empty) {
+ while (nr_enqueuers != uatomic_read(&test_enqueue_stopped)) {
+ sleep(1);
+ }
+ while (!cds_wfcq_empty(&head, &tail)) {
+ sleep(1);
+ }
+ }
+
+ test_stop_dequeue = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[3 * i];
+ tot_successful_enqueues += count_enqueuer[3 * i + 1];
+ tot_empty_dest_enqueues += count_enqueuer[3 * i + 2];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[4 * i];
+ tot_successful_dequeues += count_dequeuer[4 * i + 1];
+ tot_splice += count_dequeuer[4 * i + 2];
+ tot_dequeue_last += count_dequeuer[4 * i + 3];
+ }
+
+ test_end(&end_dequeues, &tot_dequeue_last);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "enqueues to empty dest : %llu, "
+ "successful dequeues %llu, "
+ "splice : %llu, dequeue_last : %llu\n",
+ tot_successful_enqueues,
+ tot_empty_dest_enqueues,
+ tot_successful_dequeues,
+ tot_splice, tot_dequeue_last);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu enqueues to empty dest %12llu "
+ "successful dequeues %12llu splice %12llu "
+ "dequeue_last %llu "
+ "end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_empty_dest_enqueues,
+ tot_successful_dequeues, tot_splice, tot_dequeue_last,
+ end_dequeues,
+ tot_enqueues + tot_dequeues);
+
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues) {
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+ retval = 1;
+ }
+
+ /*
+ * If only using splice to dequeue, the enqueuer should see
+ * exactly as many empty queues than the number of non-empty
+ * src splice.
+ */
+ if (tot_empty_dest_enqueues != tot_dequeue_last) {
+ printf("WARNING! Discrepancy between empty enqueue (%llu) and "
+ "number of dequeue of last element (%llu)\n",
+ tot_empty_dest_enqueues,
+ tot_dequeue_last);
+ retval = 1;
+ }
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return retval;
+}
--- /dev/null
+/*
+ * test_urcu_wfq.c
+ *
+ * Userspace RCU library - example RCU-based lock-free queue
+ *
+ * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+/* Remove deprecation warnings from test build. */
+#define CDS_WFQ_DEPRECATED
+
+#include <urcu.h>
+#include <urcu/wfqueue.h>
+
+static volatile int test_go, test_stop;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+static struct cds_wfq_queue q;
+
+void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_wfq_node *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_wfq_node_init(node);
+ cds_wfq_enqueue(&q, node);
+ URCU_TLS(nr_successful_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues));
+ return ((void*)1);
+
+}
+
+void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_wfq_node *node = cds_wfq_dequeue_blocking(&q);
+
+ if (node) {
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+
+ URCU_TLS(nr_dequeues)++;
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues),
+ URCU_TLS(nr_successful_dequeues));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ return ((void*)2);
+}
+
+void test_end(struct cds_wfq_queue *q, unsigned long long *nr_dequeues)
+{
+ struct cds_wfq_node *node;
+
+ do {
+ node = cds_wfq_dequeue_blocking(q);
+ if (node) {
+ free(node);
+ (*nr_dequeues)++;
+ }
+ } while (node);
+}
+
+void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
+ cds_wfq_init(&q);
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[2 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[2 * i];
+ tot_successful_enqueues += count_enqueuer[2 * i + 1];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[2 * i];
+ tot_successful_dequeues += count_dequeuer[2 * i + 1];
+ }
+
+ test_end(&q, &end_dequeues);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "successful dequeues %llu\n",
+ tot_successful_enqueues, tot_successful_dequeues);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu successful dequeues %12llu "
+ "end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_successful_dequeues, end_dequeues,
+ tot_enqueues + tot_dequeues);
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_wfs.c
+ *
+ * Userspace RCU library - example RCU-based lock-free stack
+ *
+ * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+#include <urcu/uatomic.h>
+#include "cpuset.h"
+#include "thread-id.h"
+
+/* hardcoded number of CPUs */
+#define NR_CPUS 16384
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+#include <urcu/wfstack.h>
+
+/*
+ * External synchronization used.
+ */
+enum test_sync {
+ TEST_SYNC_NONE = 0,
+ TEST_SYNC_MUTEX,
+};
+
+static enum test_sync test_sync;
+
+static int test_force_sync;
+
+static volatile int test_go, test_stop_enqueue, test_stop_dequeue;
+
+static unsigned long rduration;
+
+static unsigned long duration;
+
+/* read-side C.S. duration, in loops */
+static unsigned long wdelay;
+
+static inline void loop_sleep(unsigned long loops)
+{
+ while (loops-- != 0)
+ caa_cpu_relax();
+}
+
+static int verbose_mode;
+
+static int test_pop, test_pop_all, test_wait_empty;
+static int test_enqueue_stopped;
+
+#define printf_verbose(fmt, args...) \
+ do { \
+ if (verbose_mode) \
+ printf(fmt, ## args); \
+ } while (0)
+
+static unsigned int cpu_affinities[NR_CPUS];
+static unsigned int next_aff = 0;
+static int use_affinity = 0;
+
+pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void set_affinity(void)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+ int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
+
+ if (!use_affinity)
+ return;
+
+#if HAVE_SCHED_SETAFFINITY
+ ret = pthread_mutex_lock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex lock");
+ exit(-1);
+ }
+ cpu = cpu_affinities[next_aff++];
+ ret = pthread_mutex_unlock(&affinity_mutex);
+ if (ret) {
+ perror("Error in pthread mutex unlock");
+ exit(-1);
+ }
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * returns 0 if test should end.
+ */
+static int test_duration_dequeue(void)
+{
+ return !test_stop_dequeue;
+}
+
+static int test_duration_enqueue(void)
+{
+ return !test_stop_enqueue;
+}
+
+static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
+
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
+static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
+static DEFINE_URCU_TLS(unsigned long long, nr_empty_dest_enqueues);
+static DEFINE_URCU_TLS(unsigned long long, nr_pop_all);
+static DEFINE_URCU_TLS(unsigned long long, nr_pop_last);
+
+static unsigned int nr_enqueuers;
+static unsigned int nr_dequeuers;
+
+static struct cds_wfs_stack s;
+
+static void *thr_enqueuer(void *_count)
+{
+ unsigned long long *count = _count;
+ bool was_nonempty;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "enqueuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ for (;;) {
+ struct cds_wfs_node *node = malloc(sizeof(*node));
+ if (!node)
+ goto fail;
+ cds_wfs_node_init(node);
+ was_nonempty = cds_wfs_push(&s, node);
+ URCU_TLS(nr_successful_enqueues)++;
+ if (!was_nonempty)
+ URCU_TLS(nr_empty_dest_enqueues)++;
+
+ if (caa_unlikely(wdelay))
+ loop_sleep(wdelay);
+fail:
+ URCU_TLS(nr_enqueues)++;
+ if (caa_unlikely(!test_duration_enqueue()))
+ break;
+ }
+
+ uatomic_inc(&test_enqueue_stopped);
+ count[0] = URCU_TLS(nr_enqueues);
+ count[1] = URCU_TLS(nr_successful_enqueues);
+ count[2] = URCU_TLS(nr_empty_dest_enqueues);
+ printf_verbose("enqueuer thread_end, tid %lu, "
+ "enqueues %llu successful_enqueues %llu, "
+ "empty_dest_enqueues %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_enqueues),
+ URCU_TLS(nr_successful_enqueues),
+ URCU_TLS(nr_empty_dest_enqueues));
+ return ((void*)1);
+
+}
+
+static void do_test_pop(enum test_sync sync)
+{
+ struct cds_wfs_node *node;
+ int state;
+
+ if (sync == TEST_SYNC_MUTEX)
+ cds_wfs_pop_lock(&s);
+ node = __cds_wfs_pop_with_state_blocking(&s, &state);
+ if (sync == TEST_SYNC_MUTEX)
+ cds_wfs_pop_unlock(&s);
+
+ if (node) {
+ if (state & CDS_WFS_STATE_LAST)
+ URCU_TLS(nr_pop_last)++;
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ }
+ URCU_TLS(nr_dequeues)++;
+}
+
+static void do_test_pop_all(enum test_sync sync)
+{
+ struct cds_wfs_head *head;
+ struct cds_wfs_node *node, *n;
+
+ if (sync == TEST_SYNC_MUTEX)
+ cds_wfs_pop_lock(&s);
+ head = __cds_wfs_pop_all(&s);
+ if (sync == TEST_SYNC_MUTEX)
+ cds_wfs_pop_unlock(&s);
+
+ /* Check if empty */
+ if (cds_wfs_first(head) == NULL)
+ return;
+
+ URCU_TLS(nr_pop_all)++;
+ URCU_TLS(nr_pop_last)++;
+
+ cds_wfs_for_each_blocking_safe(head, node, n) {
+ free(node);
+ URCU_TLS(nr_successful_dequeues)++;
+ URCU_TLS(nr_dequeues)++;
+ }
+}
+
+static void *thr_dequeuer(void *_count)
+{
+ unsigned long long *count = _count;
+ unsigned int counter = 0;
+
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "dequeuer", urcu_get_thread_id());
+
+ set_affinity();
+
+ while (!test_go)
+ {
+ }
+ cmm_smp_mb();
+
+ assert(test_pop || test_pop_all);
+
+ for (;;) {
+ if (test_pop && test_pop_all) {
+ if (counter & 1)
+ do_test_pop(test_sync);
+ else
+ do_test_pop_all(test_sync);
+ counter++;
+ } else {
+ if (test_pop)
+ do_test_pop(test_sync);
+ else
+ do_test_pop_all(test_sync);
+ }
+
+ if (caa_unlikely(!test_duration_dequeue()))
+ break;
+ if (caa_unlikely(rduration))
+ loop_sleep(rduration);
+ }
+
+ printf_verbose("dequeuer thread_end, tid %lu, "
+ "dequeues %llu, successful_dequeues %llu "
+ "pop_all %llu pop_last %llu\n",
+ urcu_get_thread_id(),
+ URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
+ URCU_TLS(nr_pop_all),
+ URCU_TLS(nr_pop_last));
+ count[0] = URCU_TLS(nr_dequeues);
+ count[1] = URCU_TLS(nr_successful_dequeues);
+ count[2] = URCU_TLS(nr_pop_all);
+ count[3] = URCU_TLS(nr_pop_last);
+ return ((void*)2);
+}
+
+static void test_end(struct cds_wfs_stack *s, unsigned long long *nr_dequeues,
+ unsigned long long *nr_pop_last)
+{
+ struct cds_wfs_node *node;
+ int state;
+
+ do {
+ node = cds_wfs_pop_with_state_blocking(s, &state);
+ if (node) {
+ if (state & CDS_WFS_STATE_LAST)
+ (*nr_pop_last)++;
+ free(node);
+ (*nr_dequeues)++;
+ }
+ } while (node);
+}
+
+static void show_usage(int argc, char **argv)
+{
+ printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
+ argv[0]);
+ printf("OPTIONS:\n");
+ printf(" [-d delay] (enqueuer period (in loops))\n");
+ printf(" [-c duration] (dequeuer period (in loops))\n");
+ printf(" [-v] (verbose output)\n");
+ printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf(" [-p] (test pop)\n");
+ printf(" [-P] (test pop_all, enabled by default)\n");
+ printf(" [-M] (use mutex external synchronization)\n");
+ printf(" Note: default: no external synchronization used.\n");
+ printf(" [-f] (force user-provided synchronization)\n");
+ printf(" [-w] Wait for dequeuer to empty stack\n");
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+ pthread_t *tid_enqueuer, *tid_dequeuer;
+ void *tret;
+ unsigned long long *count_enqueuer, *count_dequeuer;
+ unsigned long long tot_enqueues = 0, tot_dequeues = 0;
+ unsigned long long tot_successful_enqueues = 0,
+ tot_successful_dequeues = 0,
+ tot_empty_dest_enqueues = 0,
+ tot_pop_all = 0, tot_pop_last = 0;
+ unsigned long long end_dequeues = 0;
+ int i, a, retval = 0;
+
+ if (argc < 4) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[1], "%u", &nr_dequeuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[2], "%u", &nr_enqueuers);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ err = sscanf(argv[3], "%lu", &duration);
+ if (err != 1) {
+ show_usage(argc, argv);
+ return -1;
+ }
+
+ for (i = 4; i < argc; i++) {
+ if (argv[i][0] != '-')
+ continue;
+ switch (argv[i][1]) {
+ case 'a':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ a = atoi(argv[++i]);
+ cpu_affinities[next_aff++] = a;
+ use_affinity = 1;
+ printf_verbose("Adding CPU %d affinity\n", a);
+ break;
+ case 'c':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ rduration = atol(argv[++i]);
+ break;
+ case 'd':
+ if (argc < i + 2) {
+ show_usage(argc, argv);
+ return -1;
+ }
+ wdelay = atol(argv[++i]);
+ break;
+ case 'v':
+ verbose_mode = 1;
+ break;
+ case 'p':
+ test_pop = 1;
+ break;
+ case 'P':
+ test_pop_all = 1;
+ break;
+ case 'M':
+ test_sync = TEST_SYNC_MUTEX;
+ break;
+ case 'w':
+ test_wait_empty = 1;
+ break;
+ case 'f':
+ test_force_sync = 1;
+ break;
+ }
+ }
+
+ /* activate pop_all test by default */
+ if (!test_pop && !test_pop_all)
+ test_pop_all = 1;
+
+ if (test_sync == TEST_SYNC_NONE && nr_dequeuers > 1 && test_pop) {
+ if (test_force_sync) {
+ fprintf(stderr, "[WARNING] Using pop concurrently "
+ "with other pop or pop_all without external "
+ "synchronization. Expect run-time failure.\n");
+ } else {
+ printf("Enforcing mutex synchronization\n");
+ test_sync = TEST_SYNC_MUTEX;
+ }
+ }
+
+ printf_verbose("running test for %lu seconds, %u enqueuers, "
+ "%u dequeuers.\n",
+ duration, nr_enqueuers, nr_dequeuers);
+ if (test_pop)
+ printf_verbose("pop test activated.\n");
+ if (test_pop_all)
+ printf_verbose("pop_all test activated.\n");
+ if (test_sync == TEST_SYNC_MUTEX)
+ printf_verbose("External sync: mutex.\n");
+ else
+ printf_verbose("External sync: none.\n");
+ if (test_wait_empty)
+ printf_verbose("Wait for dequeuers to empty stack.\n");
+ printf_verbose("Writer delay : %lu loops.\n", rduration);
+ printf_verbose("Reader duration : %lu loops.\n", wdelay);
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
+
+ tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
+ tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
+ count_enqueuer = calloc(nr_enqueuers, 3 * sizeof(*count_enqueuer));
+ count_dequeuer = calloc(nr_dequeuers, 4 * sizeof(*count_dequeuer));
+ cds_wfs_init(&s);
+
+ next_aff = 0;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
+ &count_enqueuer[3 * i]);
+ if (err != 0)
+ exit(1);
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
+ &count_dequeuer[4 * i]);
+ if (err != 0)
+ exit(1);
+ }
+
+ cmm_smp_mb();
+
+ test_go = 1;
+
+ for (i = 0; i < duration; i++) {
+ sleep(1);
+ if (verbose_mode)
+ write (1, ".", 1);
+ }
+
+ test_stop_enqueue = 1;
+
+ if (test_wait_empty) {
+ while (nr_enqueuers != uatomic_read(&test_enqueue_stopped)) {
+ sleep(1);
+ }
+ while (!cds_wfs_empty(&s)) {
+ sleep(1);
+ }
+ }
+
+ test_stop_dequeue = 1;
+
+ for (i = 0; i < nr_enqueuers; i++) {
+ err = pthread_join(tid_enqueuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_enqueues += count_enqueuer[3 * i];
+ tot_successful_enqueues += count_enqueuer[3 * i + 1];
+ tot_empty_dest_enqueues += count_enqueuer[3 * i + 2];
+ }
+ for (i = 0; i < nr_dequeuers; i++) {
+ err = pthread_join(tid_dequeuer[i], &tret);
+ if (err != 0)
+ exit(1);
+ tot_dequeues += count_dequeuer[4 * i];
+ tot_successful_dequeues += count_dequeuer[4 * i + 1];
+ tot_pop_all += count_dequeuer[4 * i + 2];
+ tot_pop_last += count_dequeuer[4 * i + 3];
+ }
+
+ test_end(&s, &end_dequeues, &tot_pop_last);
+
+ printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
+ tot_enqueues, tot_dequeues);
+ printf_verbose("total number of successful enqueues : %llu, "
+ "enqueues to empty dest : %llu, "
+ "successful dequeues %llu, "
+ "pop_all : %llu, pop_last : %llu\n",
+ tot_successful_enqueues,
+ tot_empty_dest_enqueues,
+ tot_successful_dequeues,
+ tot_pop_all, tot_pop_last);
+ printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
+ "nr_dequeuers %3u "
+ "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
+ "successful enqueues %12llu enqueues to empty dest %12llu "
+ "successful dequeues %12llu pop_all %12llu "
+ "pop_last %llu end_dequeues %llu nr_ops %12llu\n",
+ argv[0], duration, nr_enqueuers, wdelay,
+ nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
+ tot_successful_enqueues,
+ tot_empty_dest_enqueues,
+ tot_successful_dequeues, tot_pop_all, tot_pop_last,
+ end_dequeues,
+ tot_enqueues + tot_dequeues);
+ if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues) {
+ printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
+ "succ. dequeues + end dequeues %llu.\n",
+ tot_successful_enqueues,
+ tot_successful_dequeues + end_dequeues);
+ retval = 1;
+ }
+ /*
+ * The enqueuer should see exactly as many empty queues than the
+ * number of non-empty stacks dequeued.
+ */
+ if (tot_empty_dest_enqueues != tot_pop_last) {
+ printf("WARNING! Discrepancy between empty enqueue (%llu) and "
+ "number of pop last (%llu)\n",
+ tot_empty_dest_enqueues,
+ tot_pop_last);
+ retval = 1;
+ }
+ free(count_enqueuer);
+ free(count_dequeuer);
+ free(tid_enqueuer);
+ free(tid_dequeuer);
+ return retval;
+}
+++ /dev/null
-#
-# This file is meant to be sourced from other tests scripts.
-#
-
-if [ -x "$URCU_TEST_TIME_BIN" ]; then
- test_time_bin="$URCU_TEST_TIME_BIN"
-elif [ -x "/usr/bin/time" ]; then
- test_time_bin="/usr/bin/time"
-else
- test_time_bin=""
-fi
-
--- /dev/null
+#ifndef _INCLUDE_API_H
+#define _INCLUDE_API_H
+
+#define _GNU_SOURCE
+#include "config.h"
+
+/*
+ * common.h: Common Linux kernel-isms.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; but version 2 of the License only due
+ * to code included from the Linux kernel.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (c) 2006 Paul E. McKenney, IBM.
+ *
+ * Much code taken from the Linux kernel. For such code, the option
+ * to redistribute under later versions of GPL might not be available.
+ */
+
+#include <urcu/compiler.h>
+#include <urcu/arch.h>
+#include "cpuset.h"
+
+/*
+ * Machine parameters.
+ */
+
+#define ____cacheline_internodealigned_in_smp \
+ __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
+
+/*
+ * api_pthreads.h: API mapping to pthreads environment.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version. However, please note that much
+ * of the code in this file derives from the Linux kernel, and that such
+ * code may not be available except under GPLv2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (c) 2006 Paul E. McKenney, IBM.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/param.h>
+/* #include "atomic.h" */
+
+/*
+ * Exclusive locking primitives.
+ */
+
+typedef pthread_mutex_t spinlock_t;
+
+#define DEFINE_SPINLOCK(lock) spinlock_t lock = PTHREAD_MUTEX_INITIALIZER;
+#define __SPIN_LOCK_UNLOCKED(lockp) PTHREAD_MUTEX_INITIALIZER
+
+static void spin_lock_init(spinlock_t *sp)
+{
+ if (pthread_mutex_init(sp, NULL) != 0) {
+ perror("spin_lock_init:pthread_mutex_init");
+ exit(-1);
+ }
+}
+
+static void spin_lock(spinlock_t *sp)
+{
+ if (pthread_mutex_lock(sp) != 0) {
+ perror("spin_lock:pthread_mutex_lock");
+ exit(-1);
+ }
+}
+
+static void spin_unlock(spinlock_t *sp)
+{
+ if (pthread_mutex_unlock(sp) != 0) {
+ perror("spin_unlock:pthread_mutex_unlock");
+ exit(-1);
+ }
+}
+
+#define spin_lock_irqsave(l, f) do { f = 1; spin_lock(l); } while (0)
+#define spin_unlock_irqrestore(l, f) do { f = 0; spin_unlock(l); } while (0)
+
+/*
+ * Thread creation/destruction primitives.
+ */
+
+typedef pthread_t thread_id_t;
+
+#define NR_THREADS 128
+
+#define __THREAD_ID_MAP_EMPTY ((thread_id_t) 0)
+#define __THREAD_ID_MAP_WAITING ((thread_id_t) 1)
+thread_id_t __thread_id_map[NR_THREADS];
+spinlock_t __thread_id_map_mutex;
+
+#define for_each_thread(t) \
+ for (t = 0; t < NR_THREADS; t++)
+
+#define for_each_running_thread(t) \
+ for (t = 0; t < NR_THREADS; t++) \
+ if ((__thread_id_map[t] != __THREAD_ID_MAP_EMPTY) && \
+ (__thread_id_map[t] != __THREAD_ID_MAP_WAITING))
+
+#define for_each_tid(t, tid) \
+ for (t = 0; t < NR_THREADS; t++) \
+ if ((((tid) = __thread_id_map[t]) != __THREAD_ID_MAP_EMPTY) && \
+ ((tid) != __THREAD_ID_MAP_WAITING))
+
+pthread_key_t thread_id_key;
+
+static int __smp_thread_id(void)
+{
+ int i;
+ thread_id_t tid = pthread_self();
+
+ for (i = 0; i < NR_THREADS; i++) {
+ if (__thread_id_map[i] == tid) {
+ long v = i + 1; /* must be non-NULL. */
+
+ if (pthread_setspecific(thread_id_key, (void *)v) != 0) {
+ perror("pthread_setspecific");
+ exit(-1);
+ }
+ return i;
+ }
+ }
+ spin_lock(&__thread_id_map_mutex);
+ for (i = 0; i < NR_THREADS; i++) {
+ if (__thread_id_map[i] == tid) {
+ spin_unlock(&__thread_id_map_mutex);
+ return i;
+ }
+ }
+ spin_unlock(&__thread_id_map_mutex);
+ fprintf(stderr, "smp_thread_id: Rogue thread, id: %lu(%#lx)\n",
+ (unsigned long) tid, (unsigned long) tid);
+ exit(-1);
+}
+
+static int smp_thread_id(void)
+{
+ void *id;
+
+ id = pthread_getspecific(thread_id_key);
+ if (id == NULL)
+ return __smp_thread_id();
+ return (long)(id - 1);
+}
+
+static thread_id_t create_thread(void *(*func)(void *), void *arg)
+{
+ thread_id_t tid;
+ int i;
+
+ spin_lock(&__thread_id_map_mutex);
+ for (i = 0; i < NR_THREADS; i++) {
+ if (__thread_id_map[i] == __THREAD_ID_MAP_EMPTY)
+ break;
+ }
+ if (i >= NR_THREADS) {
+ spin_unlock(&__thread_id_map_mutex);
+ fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS);
+ exit(-1);
+ }
+ __thread_id_map[i] = __THREAD_ID_MAP_WAITING;
+ spin_unlock(&__thread_id_map_mutex);
+ if (pthread_create(&tid, NULL, func, arg) != 0) {
+ perror("create_thread:pthread_create");
+ exit(-1);
+ }
+ __thread_id_map[i] = tid;
+ return tid;
+}
+
+static void *wait_thread(thread_id_t tid)
+{
+ int i;
+ void *vp;
+
+ for (i = 0; i < NR_THREADS; i++) {
+ if (__thread_id_map[i] == tid)
+ break;
+ }
+ if (i >= NR_THREADS){
+ fprintf(stderr, "wait_thread: bad tid = %lu(%#lx)\n",
+ (unsigned long)tid, (unsigned long)tid);
+ exit(-1);
+ }
+ if (pthread_join(tid, &vp) != 0) {
+ perror("wait_thread:pthread_join");
+ exit(-1);
+ }
+ __thread_id_map[i] = __THREAD_ID_MAP_EMPTY;
+ return vp;
+}
+
+static void wait_all_threads(void)
+{
+ int i;
+ thread_id_t tid;
+
+ for (i = 1; i < NR_THREADS; i++) {
+ tid = __thread_id_map[i];
+ if (tid != __THREAD_ID_MAP_EMPTY &&
+ tid != __THREAD_ID_MAP_WAITING)
+ (void)wait_thread(tid);
+ }
+}
+
+static void run_on(int cpu)
+{
+#if HAVE_SCHED_SETAFFINITY
+ cpu_set_t mask;
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+#if SCHED_SETAFFINITY_ARGS == 2
+ sched_setaffinity(0, &mask);
+#else
+ sched_setaffinity(0, sizeof(mask), &mask);
+#endif
+#endif /* HAVE_SCHED_SETAFFINITY */
+}
+
+/*
+ * timekeeping -- very crude -- should use MONOTONIC...
+ */
+
+long long get_microseconds(void)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) != 0)
+ abort();
+ return ((long long)tv.tv_sec) * 1000000LL + (long long)tv.tv_usec;
+}
+
+/*
+ * Per-thread variables.
+ */
+
+#define DEFINE_PER_THREAD(type, name) \
+ struct { \
+ __typeof__(type) v \
+ __attribute__((__aligned__(CAA_CACHE_LINE_SIZE))); \
+ } __per_thread_##name[NR_THREADS];
+#define DECLARE_PER_THREAD(type, name) extern DEFINE_PER_THREAD(type, name)
+
+#define per_thread(name, thread) __per_thread_##name[thread].v
+#define __get_thread_var(name) per_thread(name, smp_thread_id())
+
+#define init_per_thread(name, v) \
+ do { \
+ int __i_p_t_i; \
+ for (__i_p_t_i = 0; __i_p_t_i < NR_THREADS; __i_p_t_i++) \
+ per_thread(name, __i_p_t_i) = v; \
+ } while (0)
+
+DEFINE_PER_THREAD(int, smp_processor_id);
+
+/*
+ * Bug checks.
+ */
+
+#define BUG_ON(c) do { if (!(c)) abort(); } while (0)
+
+/*
+ * Initialization -- Must be called before calling any primitives.
+ */
+
+static void smp_init(void)
+{
+ int i;
+
+ spin_lock_init(&__thread_id_map_mutex);
+ __thread_id_map[0] = pthread_self();
+ for (i = 1; i < NR_THREADS; i++)
+ __thread_id_map[i] = __THREAD_ID_MAP_EMPTY;
+ init_per_thread(smp_processor_id, 0);
+ if (pthread_key_create(&thread_id_key, NULL) != 0) {
+ perror("pthread_key_create");
+ exit(-1);
+ }
+}
+
+#endif
--- /dev/null
+#ifndef _URCU_TESTS_CPUSET_H
+#define _URCU_TESTS_CPUSET_H
+
+/*
+ * cpuset.h
+ *
+ * Userspace RCU library - test cpuset header
+ *
+ * Copyright 2009-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#if defined(HAVE_SCHED_SETAFFINITY) || defined(HAVE_CPU_SET_T) \
+ || defined(HAVE_CPU_ZERO) || defined(HAVE_CPU_SET)
+# include <sched.h>
+#endif
+
+#ifndef HAVE_CPU_SET_T
+typedef unsigned long cpu_set_t;
+#endif
+
+#ifndef HAVE_CPU_ZERO
+# define CPU_ZERO(cpuset) do { *(cpuset) = 0; } while(0)
+#endif
+
+#ifndef HAVE_CPU_SET
+# define CPU_SET(cpu, cpuset) do { *(cpuset) |= (1UL << (cpu)); } while(0)
+#endif
+
+#endif /* _URCU_TESTS_CPUSET_H */
--- /dev/null
+#ifndef _TEST_THREAD_ID_H
+#define _TEST_THREAD_ID_H
+
+/*
+ * thread-id.h
+ *
+ * Userspace RCU library - thread ID
+ *
+ * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+#ifdef __linux__
+# include <syscall.h>
+
+# if defined(_syscall0)
+_syscall0(pid_t, gettid)
+# elif defined(__NR_gettid)
+static inline pid_t gettid(void)
+{
+ return syscall(__NR_gettid);
+}
+# endif
+
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) gettid();
+}
+#elif defined(__FreeBSD__)
+# include <pthread_np.h>
+
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) pthread_getthreadid_np();
+}
+#else
+# warning "use pid as thread ID"
+static inline
+unsigned long urcu_get_thread_id(void)
+{
+ return (unsigned long) getpid();
+}
+#endif
+
+#endif /* _TEST_THREAD_ID_H */
+++ /dev/null
-#ifndef _URCU_TESTS_CPUSET_H
-#define _URCU_TESTS_CPUSET_H
-
-/*
- * cpuset.h
- *
- * Userspace RCU library - test cpuset header
- *
- * Copyright 2009-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "../config.h"
-
-#if defined(HAVE_SCHED_SETAFFINITY) || defined(HAVE_CPU_SET_T) \
- || defined(HAVE_CPU_ZERO) || defined(HAVE_CPU_SET)
-# include <sched.h>
-#endif
-
-#ifndef HAVE_CPU_SET_T
-typedef unsigned long cpu_set_t;
-#endif
-
-#ifndef HAVE_CPU_ZERO
-# define CPU_ZERO(cpuset) do { *(cpuset) = 0; } while(0)
-#endif
-
-#ifndef HAVE_CPU_SET
-# define CPU_SET(cpu, cpuset) do { *(cpuset) |= (1UL << (cpu)); } while(0)
-#endif
-
-#endif /* _URCU_TESTS_CPUSET_H */
+++ /dev/null
-/*
- * rcutorture.h: simple user-level performance/stress test of RCU.
- *
- * Usage:
- * ./rcu <nreaders> rperf [ <cpustride> ]
- * Run a read-side performance test with the specified
- * number of readers spaced by <cpustride>.
- * Thus "./rcu 16 rperf 2" would run 16 readers on even-numbered
- * CPUs from 0 to 30.
- * ./rcu <nupdaters> uperf [ <cpustride> ]
- * Run an update-side performance test with the specified
- * number of updaters and specified CPU spacing.
- * ./rcu <nreaders> perf [ <cpustride> ]
- * Run a combined read/update performance test with the specified
- * number of readers and one updater and specified CPU spacing.
- * The readers run on the low-numbered CPUs and the updater
- * of the highest-numbered CPU.
- *
- * The above tests produce output as follows:
- *
- * n_reads: 46008000 n_updates: 146026 nreaders: 2 nupdaters: 1 duration: 1
- * ns/read: 43.4707 ns/update: 6848.1
- *
- * The first line lists the total number of RCU reads and updates executed
- * during the test, the number of reader threads, the number of updater
- * threads, and the duration of the test in seconds. The second line
- * lists the average duration of each type of operation in nanoseconds,
- * or "nan" if the corresponding type of operation was not performed.
- *
- * ./rcu <nreaders> stress
- * Run a stress test with the specified number of readers and
- * one updater. None of the threads are affinitied to any
- * particular CPU.
- *
- * This test produces output as follows:
- *
- * n_reads: 114633217 n_updates: 3903415 n_mberror: 0
- * rcu_stress_count: 114618391 14826 0 0 0 0 0 0 0 0 0
- *
- * The first line lists the number of RCU read and update operations
- * executed, followed by the number of memory-ordering violations
- * (which will be zero in a correct RCU implementation). The second
- * line lists the number of readers observing progressively more stale
- * data. A correct RCU implementation will have all but the first two
- * numbers non-zero.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (c) 2008 Paul E. McKenney, IBM Corporation.
- */
-
-/*
- * Test variables.
- */
-
-#include <stdlib.h>
-
-DEFINE_PER_THREAD(long long, n_reads_pt);
-DEFINE_PER_THREAD(long long, n_updates_pt);
-
-long long n_reads = 0LL;
-long n_updates = 0L;
-int nthreadsrunning;
-char argsbuf[64];
-
-#define GOFLAG_INIT 0
-#define GOFLAG_RUN 1
-#define GOFLAG_STOP 2
-
-volatile int goflag __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
- = GOFLAG_INIT;
-
-#define RCU_READ_RUN 1000
-
-//MD
-#define RCU_READ_NESTABLE
-
-#ifdef RCU_READ_NESTABLE
-#define rcu_read_lock_nest() rcu_read_lock()
-#define rcu_read_unlock_nest() rcu_read_unlock()
-#else /* #ifdef RCU_READ_NESTABLE */
-#define rcu_read_lock_nest()
-#define rcu_read_unlock_nest()
-#endif /* #else #ifdef RCU_READ_NESTABLE */
-
-#ifdef TORTURE_QSBR
-#define mark_rcu_quiescent_state rcu_quiescent_state
-#define put_thread_offline rcu_thread_offline
-#define put_thread_online rcu_thread_online
-#endif
-
-#ifndef mark_rcu_quiescent_state
-#define mark_rcu_quiescent_state() do ; while (0)
-#endif /* #ifdef mark_rcu_quiescent_state */
-
-#ifndef put_thread_offline
-#define put_thread_offline() do ; while (0)
-#define put_thread_online() do ; while (0)
-#define put_thread_online_delay() do ; while (0)
-#else /* #ifndef put_thread_offline */
-#define put_thread_online_delay() synchronize_rcu()
-#endif /* #else #ifndef put_thread_offline */
-
-/*
- * Performance test.
- */
-
-void *rcu_read_perf_test(void *arg)
-{
- struct call_rcu_data *crdp;
- int i;
- int me = (long)arg;
- long long n_reads_local = 0;
-
- rcu_register_thread();
- run_on(me);
- uatomic_inc(&nthreadsrunning);
- put_thread_offline();
- while (goflag == GOFLAG_INIT)
- poll(NULL, 0, 1);
- put_thread_online();
- while (goflag == GOFLAG_RUN) {
- for (i = 0; i < RCU_READ_RUN; i++) {
- rcu_read_lock();
- /* rcu_read_lock_nest(); */
- /* rcu_read_unlock_nest(); */
- rcu_read_unlock();
- }
- n_reads_local += RCU_READ_RUN;
- mark_rcu_quiescent_state();
- }
- __get_thread_var(n_reads_pt) += n_reads_local;
- put_thread_offline();
- crdp = get_thread_call_rcu_data();
- set_thread_call_rcu_data(NULL);
- call_rcu_data_free(crdp);
- rcu_unregister_thread();
-
- return (NULL);
-}
-
-void *rcu_update_perf_test(void *arg)
-{
- long long n_updates_local = 0;
-
- if ((random() & 0xf00) == 0) {
- struct call_rcu_data *crdp;
-
- crdp = create_call_rcu_data(0, -1);
- if (crdp != NULL) {
- fprintf(stderr,
- "Using per-thread call_rcu() worker.\n");
- set_thread_call_rcu_data(crdp);
- }
- }
- uatomic_inc(&nthreadsrunning);
- while (goflag == GOFLAG_INIT)
- poll(NULL, 0, 1);
- while (goflag == GOFLAG_RUN) {
- synchronize_rcu();
- n_updates_local++;
- }
- __get_thread_var(n_updates_pt) += n_updates_local;
- return NULL;
-}
-
-void perftestinit(void)
-{
- init_per_thread(n_reads_pt, 0LL);
- init_per_thread(n_updates_pt, 0LL);
- uatomic_set(&nthreadsrunning, 0);
-}
-
-void perftestrun(int nthreads, int nreaders, int nupdaters)
-{
- int t;
- int duration = 1;
-
- cmm_smp_mb();
- while (uatomic_read(&nthreadsrunning) < nthreads)
- poll(NULL, 0, 1);
- goflag = GOFLAG_RUN;
- cmm_smp_mb();
- sleep(duration);
- cmm_smp_mb();
- goflag = GOFLAG_STOP;
- cmm_smp_mb();
- wait_all_threads();
- for_each_thread(t) {
- n_reads += per_thread(n_reads_pt, t);
- n_updates += per_thread(n_updates_pt, t);
- }
- printf("n_reads: %lld n_updates: %ld nreaders: %d nupdaters: %d duration: %d\n",
- n_reads, n_updates, nreaders, nupdaters, duration);
- printf("ns/read: %g ns/update: %g\n",
- ((duration * 1000*1000*1000.*(double)nreaders) /
- (double)n_reads),
- ((duration * 1000*1000*1000.*(double)nupdaters) /
- (double)n_updates));
- if (get_cpu_call_rcu_data(0)) {
- fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
- free_all_cpu_call_rcu_data();
- }
- exit(0);
-}
-
-void perftest(int nreaders, int cpustride)
-{
- int i;
- long arg;
-
- perftestinit();
- for (i = 0; i < nreaders; i++) {
- arg = (long)(i * cpustride);
- create_thread(rcu_read_perf_test, (void *)arg);
- }
- arg = (long)(i * cpustride);
- create_thread(rcu_update_perf_test, (void *)arg);
- perftestrun(i + 1, nreaders, 1);
-}
-
-void rperftest(int nreaders, int cpustride)
-{
- int i;
- long arg;
-
- perftestinit();
- init_per_thread(n_reads_pt, 0LL);
- for (i = 0; i < nreaders; i++) {
- arg = (long)(i * cpustride);
- create_thread(rcu_read_perf_test, (void *)arg);
- }
- perftestrun(i, nreaders, 0);
-}
-
-void uperftest(int nupdaters, int cpustride)
-{
- int i;
- long arg;
-
- perftestinit();
- init_per_thread(n_reads_pt, 0LL);
- for (i = 0; i < nupdaters; i++) {
- arg = (long)(i * cpustride);
- create_thread(rcu_update_perf_test, (void *)arg);
- }
- perftestrun(i, 0, nupdaters);
-}
-
-/*
- * Stress test.
- */
-
-#define RCU_STRESS_PIPE_LEN 10
-
-struct rcu_stress {
- int pipe_count;
- int mbtest;
-};
-
-struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } };
-struct rcu_stress *rcu_stress_current;
-int rcu_stress_idx = 0;
-
-int n_mberror = 0;
-DEFINE_PER_THREAD(long long [RCU_STRESS_PIPE_LEN + 1], rcu_stress_count);
-
-int garbage = 0;
-
-void *rcu_read_stress_test(void *arg)
-{
- int i;
- int itercnt = 0;
- struct rcu_stress *p;
- int pc;
-
- rcu_register_thread();
- put_thread_offline();
- while (goflag == GOFLAG_INIT)
- poll(NULL, 0, 1);
- put_thread_online();
- while (goflag == GOFLAG_RUN) {
- rcu_read_lock();
- p = rcu_dereference(rcu_stress_current);
- if (p->mbtest == 0)
- n_mberror++;
- rcu_read_lock_nest();
- for (i = 0; i < 100; i++)
- garbage++;
- rcu_read_unlock_nest();
- pc = p->pipe_count;
- rcu_read_unlock();
- if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0))
- pc = RCU_STRESS_PIPE_LEN;
- __get_thread_var(rcu_stress_count)[pc]++;
- __get_thread_var(n_reads_pt)++;
- mark_rcu_quiescent_state();
- if ((++itercnt % 0x1000) == 0) {
- put_thread_offline();
- put_thread_online_delay();
- put_thread_online();
- }
- }
- put_thread_offline();
- rcu_unregister_thread();
-
- return (NULL);
-}
-
-static pthread_mutex_t call_rcu_test_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t call_rcu_test_cond = PTHREAD_COND_INITIALIZER;
-
-void rcu_update_stress_test_rcu(struct rcu_head *head)
-{
- if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
- perror("pthread_mutex_lock");
- exit(-1);
- }
- if (pthread_cond_signal(&call_rcu_test_cond) != 0) {
- perror("pthread_cond_signal");
- exit(-1);
- }
- if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
- perror("pthread_mutex_unlock");
- exit(-1);
- }
-}
-
-void *rcu_update_stress_test(void *arg)
-{
- int i;
- struct rcu_stress *p;
- struct rcu_head rh;
-
- while (goflag == GOFLAG_INIT)
- poll(NULL, 0, 1);
- while (goflag == GOFLAG_RUN) {
- i = rcu_stress_idx + 1;
- if (i >= RCU_STRESS_PIPE_LEN)
- i = 0;
- p = &rcu_stress_array[i];
- p->mbtest = 0;
- cmm_smp_mb();
- p->pipe_count = 0;
- p->mbtest = 1;
- rcu_assign_pointer(rcu_stress_current, p);
- rcu_stress_idx = i;
- for (i = 0; i < RCU_STRESS_PIPE_LEN; i++)
- if (i != rcu_stress_idx)
- rcu_stress_array[i].pipe_count++;
- if (n_updates & 0x1)
- synchronize_rcu();
- else {
- if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
- perror("pthread_mutex_lock");
- exit(-1);
- }
- call_rcu(&rh, rcu_update_stress_test_rcu);
- if (pthread_cond_wait(&call_rcu_test_cond,
- &call_rcu_test_mutex) != 0) {
- perror("pthread_cond_wait");
- exit(-1);
- }
- if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
- perror("pthread_mutex_unlock");
- exit(-1);
- }
- }
- n_updates++;
- }
- return NULL;
-}
-
-void *rcu_fake_update_stress_test(void *arg)
-{
- if ((random() & 0xf00) == 0) {
- struct call_rcu_data *crdp;
-
- crdp = create_call_rcu_data(0, -1);
- if (crdp != NULL) {
- fprintf(stderr,
- "Using per-thread call_rcu() worker.\n");
- set_thread_call_rcu_data(crdp);
- }
- }
- while (goflag == GOFLAG_INIT)
- poll(NULL, 0, 1);
- while (goflag == GOFLAG_RUN) {
- synchronize_rcu();
- poll(NULL, 0, 1);
- }
- return NULL;
-}
-
-void stresstest(int nreaders)
-{
- int i;
- int t;
- long long *p;
- long long sum;
-
- init_per_thread(n_reads_pt, 0LL);
- for_each_thread(t) {
- p = &per_thread(rcu_stress_count,t)[0];
- for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++)
- p[i] = 0LL;
- }
- rcu_stress_current = &rcu_stress_array[0];
- rcu_stress_current->pipe_count = 0;
- rcu_stress_current->mbtest = 1;
- for (i = 0; i < nreaders; i++)
- create_thread(rcu_read_stress_test, NULL);
- create_thread(rcu_update_stress_test, NULL);
- for (i = 0; i < 5; i++)
- create_thread(rcu_fake_update_stress_test, NULL);
- cmm_smp_mb();
- goflag = GOFLAG_RUN;
- cmm_smp_mb();
- sleep(10);
- cmm_smp_mb();
- goflag = GOFLAG_STOP;
- cmm_smp_mb();
- wait_all_threads();
- for_each_thread(t)
- n_reads += per_thread(n_reads_pt, t);
- printf("n_reads: %lld n_updates: %ld n_mberror: %d\n",
- n_reads, n_updates, n_mberror);
- printf("rcu_stress_count:");
- for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) {
- sum = 0LL;
- for_each_thread(t) {
- sum += per_thread(rcu_stress_count, t)[i];
- }
- printf(" %lld", sum);
- }
- printf("\n");
- if (get_cpu_call_rcu_data(0)) {
- fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
- free_all_cpu_call_rcu_data();
- }
- exit(0);
-}
-
-/*
- * Mainprogram.
- */
-
-void usage(int argc, char *argv[])
-{
- fprintf(stderr, "Usage: %s [nreaders [ perf | stress ] ]\n", argv[0]);
- exit(-1);
-}
-
-int main(int argc, char *argv[])
-{
- int nreaders = 1;
- int cpustride = 1;
-
- smp_init();
- //rcu_init();
- srandom(time(NULL));
- if (random() & 0x100) {
- fprintf(stderr, "Allocating per-CPU call_rcu threads.\n");
- if (create_all_cpu_call_rcu_data(0))
- perror("create_all_cpu_call_rcu_data");
- }
-
-#ifdef DEBUG_YIELD
- yield_active |= YIELD_READ;
- yield_active |= YIELD_WRITE;
-#endif
-
- if (argc > 1) {
- nreaders = strtoul(argv[1], NULL, 0);
- if (argc == 2)
- perftest(nreaders, cpustride);
- if (argc > 3)
- cpustride = strtoul(argv[3], NULL, 0);
- if (strcmp(argv[2], "perf") == 0)
- perftest(nreaders, cpustride);
- else if (strcmp(argv[2], "rperf") == 0)
- rperftest(nreaders, cpustride);
- else if (strcmp(argv[2], "uperf") == 0)
- uperftest(nreaders, cpustride);
- else if (strcmp(argv[2], "stress") == 0)
- stresstest(nreaders);
- usage(argc, argv);
- }
- perftest(nreaders, cpustride);
- return 0;
-}
--- /dev/null
+AM_LDFLAGS=-lpthread
+AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g
+
+noinst_PROGRAMS = test_urcu_fork \
+ rcutorture_urcu \
+ rcutorture_urcu_signal \
+ rcutorture_urcu_mb \
+ rcutorture_urcu_bp \
+ rcutorture_urcu_qsbr
+
+noinst_HEADERS = rcutorture.h
+
+if COMPAT_ARCH
+COMPAT=$(top_srcdir)/compat_arch_@ARCHTYPE@.c
+else
+COMPAT=
+endif
+
+if COMPAT_FUTEX
+COMPAT+=$(top_srcdir)/compat_futex.c
+endif
+
+URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_MB uses urcu.c but -DRCU_MB must be defined
+URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined
+URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+
+URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
+URCU_LIB=$(top_builddir)/liburcu.la
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+
+test_urcu_fork_SOURCES = test_urcu_fork.c $(URCU)
+
+rcutorture_urcu_SOURCES = urcutorture.c
+rcutorture_urcu_CFLAGS = -DRCU_MEMBARRIER $(AM_CFLAGS)
+rcutorture_urcu_LDADD = $(URCU)
+
+rcutorture_urcu_mb_SOURCES = urcutorture.c
+rcutorture_urcu_mb_CFLAGS = -DRCU_MB $(AM_CFLAGS)
+rcutorture_urcu_mb_LDADD = $(URCU_MB_LIB)
+
+rcutorture_urcu_qsbr_SOURCES = urcutorture.c
+rcutorture_urcu_qsbr_CFLAGS = -DTORTURE_QSBR -DRCU_QSBR $(AM_CFLAGS)
+rcutorture_urcu_qsbr_LDADD = $(URCU_QSBR_LIB)
+
+rcutorture_urcu_signal_SOURCES = urcutorture.c
+rcutorture_urcu_signal_CFLAGS = -DRCU_SIGNAL $(AM_CFLAGS)
+rcutorture_urcu_signal_LDADD = $(URCU_SIGNAL_LIB)
+
+rcutorture_urcu_bp_SOURCES = urcutorture.c
+rcutorture_urcu_bp_CFLAGS = -DRCU_BP $(AM_CFLAGS)
+rcutorture_urcu_bp_LDADD = $(URCU_BP_LIB)
+
+urcutorture.c: ../common/api.h
+
+.PHONY: regtest
+
+# For now, run the benchmarks too as regression tests.
+# TODO: split benchmarks from regression tests
+regtest:
+ ./test_urcu_fork
+ ./rcutorture_urcu
+ ./rcutorture_urcu_signal
+ ./rcutorture_urcu_mb
+ ./rcutorture_urcu_bp
+ ./rcutorture_urcu_qsbr
+ cd ../benchmark && ./runall.sh && cd ..
--- /dev/null
+/*
+ * rcutorture.h: simple user-level performance/stress test of RCU.
+ *
+ * Usage:
+ * ./rcu <nreaders> rperf [ <cpustride> ]
+ * Run a read-side performance test with the specified
+ * number of readers spaced by <cpustride>.
+ * Thus "./rcu 16 rperf 2" would run 16 readers on even-numbered
+ * CPUs from 0 to 30.
+ * ./rcu <nupdaters> uperf [ <cpustride> ]
+ * Run an update-side performance test with the specified
+ * number of updaters and specified CPU spacing.
+ * ./rcu <nreaders> perf [ <cpustride> ]
+ * Run a combined read/update performance test with the specified
+ * number of readers and one updater and specified CPU spacing.
+ * The readers run on the low-numbered CPUs and the updater
+ * of the highest-numbered CPU.
+ *
+ * The above tests produce output as follows:
+ *
+ * n_reads: 46008000 n_updates: 146026 nreaders: 2 nupdaters: 1 duration: 1
+ * ns/read: 43.4707 ns/update: 6848.1
+ *
+ * The first line lists the total number of RCU reads and updates executed
+ * during the test, the number of reader threads, the number of updater
+ * threads, and the duration of the test in seconds. The second line
+ * lists the average duration of each type of operation in nanoseconds,
+ * or "nan" if the corresponding type of operation was not performed.
+ *
+ * ./rcu <nreaders> stress
+ * Run a stress test with the specified number of readers and
+ * one updater. None of the threads are affinitied to any
+ * particular CPU.
+ *
+ * This test produces output as follows:
+ *
+ * n_reads: 114633217 n_updates: 3903415 n_mberror: 0
+ * rcu_stress_count: 114618391 14826 0 0 0 0 0 0 0 0 0
+ *
+ * The first line lists the number of RCU read and update operations
+ * executed, followed by the number of memory-ordering violations
+ * (which will be zero in a correct RCU implementation). The second
+ * line lists the number of readers observing progressively more stale
+ * data. A correct RCU implementation will have all but the first two
+ * numbers non-zero.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (c) 2008 Paul E. McKenney, IBM Corporation.
+ */
+
+/*
+ * Test variables.
+ */
+
+#include <stdlib.h>
+
+DEFINE_PER_THREAD(long long, n_reads_pt);
+DEFINE_PER_THREAD(long long, n_updates_pt);
+
+long long n_reads = 0LL;
+long n_updates = 0L;
+int nthreadsrunning;
+char argsbuf[64];
+
+#define GOFLAG_INIT 0
+#define GOFLAG_RUN 1
+#define GOFLAG_STOP 2
+
+volatile int goflag __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
+ = GOFLAG_INIT;
+
+#define RCU_READ_RUN 1000
+
+//MD
+#define RCU_READ_NESTABLE
+
+#ifdef RCU_READ_NESTABLE
+#define rcu_read_lock_nest() rcu_read_lock()
+#define rcu_read_unlock_nest() rcu_read_unlock()
+#else /* #ifdef RCU_READ_NESTABLE */
+#define rcu_read_lock_nest()
+#define rcu_read_unlock_nest()
+#endif /* #else #ifdef RCU_READ_NESTABLE */
+
+#ifdef TORTURE_QSBR
+#define mark_rcu_quiescent_state rcu_quiescent_state
+#define put_thread_offline rcu_thread_offline
+#define put_thread_online rcu_thread_online
+#endif
+
+#ifndef mark_rcu_quiescent_state
+#define mark_rcu_quiescent_state() do ; while (0)
+#endif /* #ifdef mark_rcu_quiescent_state */
+
+#ifndef put_thread_offline
+#define put_thread_offline() do ; while (0)
+#define put_thread_online() do ; while (0)
+#define put_thread_online_delay() do ; while (0)
+#else /* #ifndef put_thread_offline */
+#define put_thread_online_delay() synchronize_rcu()
+#endif /* #else #ifndef put_thread_offline */
+
+/*
+ * Performance test.
+ */
+
+void *rcu_read_perf_test(void *arg)
+{
+ struct call_rcu_data *crdp;
+ int i;
+ int me = (long)arg;
+ long long n_reads_local = 0;
+
+ rcu_register_thread();
+ run_on(me);
+ uatomic_inc(&nthreadsrunning);
+ put_thread_offline();
+ while (goflag == GOFLAG_INIT)
+ poll(NULL, 0, 1);
+ put_thread_online();
+ while (goflag == GOFLAG_RUN) {
+ for (i = 0; i < RCU_READ_RUN; i++) {
+ rcu_read_lock();
+ /* rcu_read_lock_nest(); */
+ /* rcu_read_unlock_nest(); */
+ rcu_read_unlock();
+ }
+ n_reads_local += RCU_READ_RUN;
+ mark_rcu_quiescent_state();
+ }
+ __get_thread_var(n_reads_pt) += n_reads_local;
+ put_thread_offline();
+ crdp = get_thread_call_rcu_data();
+ set_thread_call_rcu_data(NULL);
+ call_rcu_data_free(crdp);
+ rcu_unregister_thread();
+
+ return (NULL);
+}
+
+void *rcu_update_perf_test(void *arg)
+{
+ long long n_updates_local = 0;
+
+ if ((random() & 0xf00) == 0) {
+ struct call_rcu_data *crdp;
+
+ crdp = create_call_rcu_data(0, -1);
+ if (crdp != NULL) {
+ fprintf(stderr,
+ "Using per-thread call_rcu() worker.\n");
+ set_thread_call_rcu_data(crdp);
+ }
+ }
+ uatomic_inc(&nthreadsrunning);
+ while (goflag == GOFLAG_INIT)
+ poll(NULL, 0, 1);
+ while (goflag == GOFLAG_RUN) {
+ synchronize_rcu();
+ n_updates_local++;
+ }
+ __get_thread_var(n_updates_pt) += n_updates_local;
+ return NULL;
+}
+
+void perftestinit(void)
+{
+ init_per_thread(n_reads_pt, 0LL);
+ init_per_thread(n_updates_pt, 0LL);
+ uatomic_set(&nthreadsrunning, 0);
+}
+
+void perftestrun(int nthreads, int nreaders, int nupdaters)
+{
+ int t;
+ int duration = 1;
+
+ cmm_smp_mb();
+ while (uatomic_read(&nthreadsrunning) < nthreads)
+ poll(NULL, 0, 1);
+ goflag = GOFLAG_RUN;
+ cmm_smp_mb();
+ sleep(duration);
+ cmm_smp_mb();
+ goflag = GOFLAG_STOP;
+ cmm_smp_mb();
+ wait_all_threads();
+ for_each_thread(t) {
+ n_reads += per_thread(n_reads_pt, t);
+ n_updates += per_thread(n_updates_pt, t);
+ }
+ printf("n_reads: %lld n_updates: %ld nreaders: %d nupdaters: %d duration: %d\n",
+ n_reads, n_updates, nreaders, nupdaters, duration);
+ printf("ns/read: %g ns/update: %g\n",
+ ((duration * 1000*1000*1000.*(double)nreaders) /
+ (double)n_reads),
+ ((duration * 1000*1000*1000.*(double)nupdaters) /
+ (double)n_updates));
+ if (get_cpu_call_rcu_data(0)) {
+ fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
+ free_all_cpu_call_rcu_data();
+ }
+ exit(0);
+}
+
+void perftest(int nreaders, int cpustride)
+{
+ int i;
+ long arg;
+
+ perftestinit();
+ for (i = 0; i < nreaders; i++) {
+ arg = (long)(i * cpustride);
+ create_thread(rcu_read_perf_test, (void *)arg);
+ }
+ arg = (long)(i * cpustride);
+ create_thread(rcu_update_perf_test, (void *)arg);
+ perftestrun(i + 1, nreaders, 1);
+}
+
+void rperftest(int nreaders, int cpustride)
+{
+ int i;
+ long arg;
+
+ perftestinit();
+ init_per_thread(n_reads_pt, 0LL);
+ for (i = 0; i < nreaders; i++) {
+ arg = (long)(i * cpustride);
+ create_thread(rcu_read_perf_test, (void *)arg);
+ }
+ perftestrun(i, nreaders, 0);
+}
+
+void uperftest(int nupdaters, int cpustride)
+{
+ int i;
+ long arg;
+
+ perftestinit();
+ init_per_thread(n_reads_pt, 0LL);
+ for (i = 0; i < nupdaters; i++) {
+ arg = (long)(i * cpustride);
+ create_thread(rcu_update_perf_test, (void *)arg);
+ }
+ perftestrun(i, 0, nupdaters);
+}
+
+/*
+ * Stress test.
+ */
+
+#define RCU_STRESS_PIPE_LEN 10
+
+struct rcu_stress {
+ int pipe_count;
+ int mbtest;
+};
+
+struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } };
+struct rcu_stress *rcu_stress_current;
+int rcu_stress_idx = 0;
+
+int n_mberror = 0;
+DEFINE_PER_THREAD(long long [RCU_STRESS_PIPE_LEN + 1], rcu_stress_count);
+
+int garbage = 0;
+
+void *rcu_read_stress_test(void *arg)
+{
+ int i;
+ int itercnt = 0;
+ struct rcu_stress *p;
+ int pc;
+
+ rcu_register_thread();
+ put_thread_offline();
+ while (goflag == GOFLAG_INIT)
+ poll(NULL, 0, 1);
+ put_thread_online();
+ while (goflag == GOFLAG_RUN) {
+ rcu_read_lock();
+ p = rcu_dereference(rcu_stress_current);
+ if (p->mbtest == 0)
+ n_mberror++;
+ rcu_read_lock_nest();
+ for (i = 0; i < 100; i++)
+ garbage++;
+ rcu_read_unlock_nest();
+ pc = p->pipe_count;
+ rcu_read_unlock();
+ if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0))
+ pc = RCU_STRESS_PIPE_LEN;
+ __get_thread_var(rcu_stress_count)[pc]++;
+ __get_thread_var(n_reads_pt)++;
+ mark_rcu_quiescent_state();
+ if ((++itercnt % 0x1000) == 0) {
+ put_thread_offline();
+ put_thread_online_delay();
+ put_thread_online();
+ }
+ }
+ put_thread_offline();
+ rcu_unregister_thread();
+
+ return (NULL);
+}
+
+static pthread_mutex_t call_rcu_test_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t call_rcu_test_cond = PTHREAD_COND_INITIALIZER;
+
+void rcu_update_stress_test_rcu(struct rcu_head *head)
+{
+ if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
+ perror("pthread_mutex_lock");
+ exit(-1);
+ }
+ if (pthread_cond_signal(&call_rcu_test_cond) != 0) {
+ perror("pthread_cond_signal");
+ exit(-1);
+ }
+ if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
+ perror("pthread_mutex_unlock");
+ exit(-1);
+ }
+}
+
+void *rcu_update_stress_test(void *arg)
+{
+ int i;
+ struct rcu_stress *p;
+ struct rcu_head rh;
+
+ while (goflag == GOFLAG_INIT)
+ poll(NULL, 0, 1);
+ while (goflag == GOFLAG_RUN) {
+ i = rcu_stress_idx + 1;
+ if (i >= RCU_STRESS_PIPE_LEN)
+ i = 0;
+ p = &rcu_stress_array[i];
+ p->mbtest = 0;
+ cmm_smp_mb();
+ p->pipe_count = 0;
+ p->mbtest = 1;
+ rcu_assign_pointer(rcu_stress_current, p);
+ rcu_stress_idx = i;
+ for (i = 0; i < RCU_STRESS_PIPE_LEN; i++)
+ if (i != rcu_stress_idx)
+ rcu_stress_array[i].pipe_count++;
+ if (n_updates & 0x1)
+ synchronize_rcu();
+ else {
+ if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
+ perror("pthread_mutex_lock");
+ exit(-1);
+ }
+ call_rcu(&rh, rcu_update_stress_test_rcu);
+ if (pthread_cond_wait(&call_rcu_test_cond,
+ &call_rcu_test_mutex) != 0) {
+ perror("pthread_cond_wait");
+ exit(-1);
+ }
+ if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
+ perror("pthread_mutex_unlock");
+ exit(-1);
+ }
+ }
+ n_updates++;
+ }
+ return NULL;
+}
+
+void *rcu_fake_update_stress_test(void *arg)
+{
+ if ((random() & 0xf00) == 0) {
+ struct call_rcu_data *crdp;
+
+ crdp = create_call_rcu_data(0, -1);
+ if (crdp != NULL) {
+ fprintf(stderr,
+ "Using per-thread call_rcu() worker.\n");
+ set_thread_call_rcu_data(crdp);
+ }
+ }
+ while (goflag == GOFLAG_INIT)
+ poll(NULL, 0, 1);
+ while (goflag == GOFLAG_RUN) {
+ synchronize_rcu();
+ poll(NULL, 0, 1);
+ }
+ return NULL;
+}
+
+void stresstest(int nreaders)
+{
+ int i;
+ int t;
+ long long *p;
+ long long sum;
+
+ init_per_thread(n_reads_pt, 0LL);
+ for_each_thread(t) {
+ p = &per_thread(rcu_stress_count,t)[0];
+ for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++)
+ p[i] = 0LL;
+ }
+ rcu_stress_current = &rcu_stress_array[0];
+ rcu_stress_current->pipe_count = 0;
+ rcu_stress_current->mbtest = 1;
+ for (i = 0; i < nreaders; i++)
+ create_thread(rcu_read_stress_test, NULL);
+ create_thread(rcu_update_stress_test, NULL);
+ for (i = 0; i < 5; i++)
+ create_thread(rcu_fake_update_stress_test, NULL);
+ cmm_smp_mb();
+ goflag = GOFLAG_RUN;
+ cmm_smp_mb();
+ sleep(10);
+ cmm_smp_mb();
+ goflag = GOFLAG_STOP;
+ cmm_smp_mb();
+ wait_all_threads();
+ for_each_thread(t)
+ n_reads += per_thread(n_reads_pt, t);
+ printf("n_reads: %lld n_updates: %ld n_mberror: %d\n",
+ n_reads, n_updates, n_mberror);
+ printf("rcu_stress_count:");
+ for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) {
+ sum = 0LL;
+ for_each_thread(t) {
+ sum += per_thread(rcu_stress_count, t)[i];
+ }
+ printf(" %lld", sum);
+ }
+ printf("\n");
+ if (get_cpu_call_rcu_data(0)) {
+ fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
+ free_all_cpu_call_rcu_data();
+ }
+ exit(0);
+}
+
+/*
+ * Mainprogram.
+ */
+
+void usage(int argc, char *argv[])
+{
+ fprintf(stderr, "Usage: %s [nreaders [ perf | stress ] ]\n", argv[0]);
+ exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+ int nreaders = 1;
+ int cpustride = 1;
+
+ smp_init();
+ //rcu_init();
+ srandom(time(NULL));
+ if (random() & 0x100) {
+ fprintf(stderr, "Allocating per-CPU call_rcu threads.\n");
+ if (create_all_cpu_call_rcu_data(0))
+ perror("create_all_cpu_call_rcu_data");
+ }
+
+#ifdef DEBUG_YIELD
+ yield_active |= YIELD_READ;
+ yield_active |= YIELD_WRITE;
+#endif
+
+ if (argc > 1) {
+ nreaders = strtoul(argv[1], NULL, 0);
+ if (argc == 2)
+ perftest(nreaders, cpustride);
+ if (argc > 3)
+ cpustride = strtoul(argv[3], NULL, 0);
+ if (strcmp(argv[2], "perf") == 0)
+ perftest(nreaders, cpustride);
+ else if (strcmp(argv[2], "rperf") == 0)
+ rperftest(nreaders, cpustride);
+ else if (strcmp(argv[2], "uperf") == 0)
+ uperftest(nreaders, cpustride);
+ else if (strcmp(argv[2], "stress") == 0)
+ stresstest(nreaders);
+ usage(argc, argv);
+ }
+ perftest(nreaders, cpustride);
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_fork.c
+ *
+ * Userspace RCU library - test program (fork)
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _GNU_SOURCE
+#include "config.h"
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sched.h>
+#include <errno.h>
+
+#include <urcu/arch.h>
+#include <urcu/tls-compat.h>
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#else
+#define rcu_debug_yield_read()
+#endif
+#include <urcu.h>
+
+struct test_node {
+ int somedata;
+ struct rcu_head head;
+};
+
+static void cb(struct rcu_head *head)
+{
+ struct test_node *node;
+
+ fprintf(stderr, "rcu callback invoked in pid: %d\n",
+ (int) getpid());
+ node = caa_container_of(head, struct test_node, head);
+ free(node);
+}
+
+static void test_rcu(void)
+{
+ struct test_node *node;
+
+ rcu_register_thread();
+
+ synchronize_rcu();
+
+ rcu_read_lock();
+ rcu_read_unlock();
+
+ node = malloc(sizeof(*node));
+ assert(node);
+
+ call_rcu(&node->head, cb);
+
+ synchronize_rcu();
+
+ rcu_unregister_thread();
+}
+
+int main(int argc, char **argv)
+{
+ pid_t pid;
+ int ret;
+
+#if 0
+ /* pthread_atfork does not work with malloc/free in callbacks */
+ ret = pthread_atfork(call_rcu_before_fork,
+ call_rcu_after_fork_parent,
+ call_rcu_after_fork_child);
+ if (ret) {
+ errno = ret;
+ perror("pthread_atfork");
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ test_rcu();
+
+ synchronize_rcu();
+
+ fprintf(stderr, "%s parent pid: %d, before fork\n",
+ argv[0], (int) getpid());
+
+ call_rcu_before_fork();
+ pid = fork();
+
+ if (pid == 0) {
+ /* child */
+ call_rcu_after_fork_child();
+ fprintf(stderr, "%s child pid: %d, after fork\n",
+ argv[0], (int) getpid());
+ test_rcu();
+ fprintf(stderr, "%s child pid: %d, after rcu test\n",
+ argv[0], (int) getpid());
+ } else if (pid > 0) {
+ int status;
+
+ /* parent */
+ call_rcu_after_fork_parent();
+ fprintf(stderr, "%s parent pid: %d, after fork\n",
+ argv[0], (int) getpid());
+ test_rcu();
+ fprintf(stderr, "%s parent pid: %d, after rcu test\n",
+ argv[0], (int) getpid());
+ for (;;) {
+ pid = wait(&status);
+ if (WIFEXITED(status)) {
+ fprintf(stderr, "child %u exited normally with status %u\n",
+ pid, WEXITSTATUS(status));
+ break;
+ } else if (WIFSIGNALED(status)) {
+ fprintf(stderr, "child %u was terminated by signal %u\n",
+ pid, WTERMSIG(status));
+ break;
+ } else {
+ continue;
+ }
+ }
+ } else {
+ perror("fork");
+ exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+}
--- /dev/null
+#define _GNU_SOURCE
+#include <string.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <urcu/arch.h>
+#include "api.h"
+#define _LGPL_SOURCE
+
+#ifdef RCU_MEMBARRIER
+#include <urcu.h>
+#endif
+#ifdef RCU_SIGNAL
+#include <urcu.h>
+#endif
+#ifdef RCU_MB
+#include <urcu.h>
+#endif
+#ifdef RCU_QSBR
+#include <urcu-qsbr.h>
+#endif
+#ifdef RCU_BP
+#include <urcu-bp.h>
+#endif
+
+#include <urcu/uatomic.h>
+#include <urcu/rculist.h>
+#include "rcutorture.h"
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-NUM_CPUS=8
-
-#extra options, e.g. for setting affinity on even CPUs :
-#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-#stride 1
-#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-#stride 2
-#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-#stride 4
-#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-#stride 8
-#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-
-#Vary update fraction
-#x: vary update fraction from 0 to 0.0001
- #fix number of readers and reader C.S. length, vary delay between updates
-#y: ops/s
-
-rm -f runall.log
-rm -fr runall.detail.log
-
-
-echo Executing batch RCU test
-
-DURATION=10
-BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
- 131072 262144"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f batch-rcu.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for BATCH_SIZE in ${BATCH_ARRAY}; do
- echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
- (./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log) || exit 1
-done
-
-#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE **
-EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
-
-echo Executing update fraction test
-
-DURATION=10
-WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
- 65536 131072 262144 524288 1048576 2097152 4194304 8388608
- 16777216 33554432 67108864 134217728"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f update-fraction.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for WDELAY in ${WDELAY_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
- (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log) || exit 1
-done
-
-#Test scalability :
-# x: vary number of readers from 0 to num cpus
-# y: ops/s
-# 0 writer.
-
-echo Executing scalability test
-
-NR_WRITERS=0
-DURATION=10
-
-rm -f scalability.log
-
-for NR_READERS in $(seq 1 ${NUM_CPUS}); do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
- (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log) || exit 1
-done
-
-
-# x: Vary reader C.S. length from 0 to 100 us
-# y: ops/s
-# 8 readers
-# 0 writers
-
-echo Executing reader C.S. length test
-
-NR_READERS=${NUM_CPUS}
-NR_WRITERS=0
-DURATION=10
-#in loops.
-READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
-
-rm -f readercslen.log
-
-for READERCSLEN in ${READERCSLEN_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log
- (./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log) || exit 1
-done
-
-echo Executing multi-flavor RCU test
-./test_urcu_multiflavor || exit 1
-./test_urcu_multiflavor_dynlink || exit 1
-
-echo Executing Hash table test
-./runhash.sh || exit 1
+++ /dev/null
-#!/bin/sh
-
-# TODO: missing tests:
-# - send kill signals during tests to change the behavior between
-# add/remove/random
-# - validate that "nr_leaked" is always 0 in SUMMARY for all tests
-
-# 30 seconds per test
-TIME_UNITS=30
-
-TESTPROG=./test_urcu_hash
-
-#thread multiplier
-THREAD_MUL=1
-
-EXTRA_PARAMS=-v
-
-# ** test update coherency with single-value table
-
-# rw test, single key, replace and del randomly, 4 threads, auto resize.
-# key range: init, lookup, and update: 0 to 0
-${TESTPROG} 0 $((4*${THREAD_MUL})) ${TIME_UNITS} -A -s -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
-
-# rw test, single key, add unique and del randomly, 4 threads, auto resize.
-# key range: init, lookup, and update: 0 to 0
-${TESTPROG} 0 $((4*${THREAD_MUL})) ${TIME_UNITS} -A -u -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
-
-# rw test, single key, replace and del randomly, 2 lookup threads, 2 update threads, auto resize.
-# key range: init, lookup, and update: 0 to 0
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -s -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
-
-# rw test, single key, add and del randomly, 2 lookup threads, 2 update threads, auto resize.
-# key range: init, lookup, and update: 0 to 0
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -M 1 -N 1 -O 1 ${EXTRA_PARAMS} || exit 1
-
-
-# ** test updates vs lookups with default table
-
-# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, lookup, and update: 0 to 999999
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, lookup, and update: 0 to 999999
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -s ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add_unique and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, lookup, and update: 0 to 999999
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -u ${EXTRA_PARAMS} || exit 1
-
-
-# test memory management backends
-
-# rw test, 2 lookup, 2 update threads, add only, auto resize.
-# max buckets: 1048576
-# key range: init, lookup, and update: 0 to 99999999
-# mm backend: "order"
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
- -M 100000000 -N 100000000 -O 100000000 -B order ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add only, auto resize.
-# max buckets: 1048576
-# key range: init, lookup, and update: 0 to 99999999
-# mm backend: "chunk"
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
- -M 100000000 -N 100000000 -O 100000000 -B chunk ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add only, auto resize.
-# max buckets: 1048576
-# key range: init, lookup, and update: 0 to 99999999
-# mm backend: "mmap"
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A -m 1 -n 1048576 -i \
- -M 100000000 -N 100000000 -O 100000000 -B mmap ${EXTRA_PARAMS} || exit 1
-
-
-# ** key range tests
-
-# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, and update: 0 to 999999
-# key range: lookup: 1000000 to 1999999
-# NOTE: reader threads in this test should never have a successful
-# lookup. TODO
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -R 1000000 ${EXTRA_PARAMS} || exit 1
-
-# ** small key range
-
-# rw test, 2 lookup, 2 update threads, add and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, update, and lookups: 0 to 9
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -M 10 -N 10 -O 10 ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add_unique and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, update, and lookups: 0 to 9
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -M 10 -N 10 -O 10 -u ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
-# max 1048576 buckets
-# key range: init, update, and lookups: 0 to 9
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -M 10 -N 10 -O 10 -s ${EXTRA_PARAMS} || exit 1
-
-# ** lookup for known keys
-
-# rw test, 2 lookup, 2 update threads, add_replace and del randomly, auto resize.
-# max 1048576 buckets
-# lookup range is entirely populated.
-# key range: init, and lookups: 0 to 9
-# key range: updates: 10 to 19
-# NOTE: reader threads in this test should always have successful
-# lookups. TODO
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -M 10 -N 10 -O 10 -R 0 -T 0 -S 10 -k 10 -s ${EXTRA_PARAMS} || exit 1
-
-# ** Uniqueness test
-
-# rw test, 2 lookup, 2 update threads, add_unique, add_replace and del randomly, auto resize.
-# max 1048576 buckets
-# asserts that no duplicates are observed by reader threads
-# standard length hash chains
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -U ${EXTRA_PARAMS} || exit 1
-
-# rw test, 2 lookup, 2 update threads, add_unique, add_replace and del randomly, auto resize.
-# max 1048576 buckets
-# asserts that no duplicates are observed by reader threads
-# create long hash chains: using modulo 4 on keys as hash
-${TESTPROG} $((2*${THREAD_MUL})) $((2*${THREAD_MUL})) ${TIME_UNITS} -A \
- -U -C 4 ${EXTRA_PARAMS} || exit 1
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-NUM_CPUS=64
-
-#extra options, e.g. for setting affinity on even CPUs :
-EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-#stride 1
-#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-#stride 2
-#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-#stride 4
-#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-#stride 8
-#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-
-#Vary update fraction
-#x: vary update fraction from 0 to 0.0001
- #fix number of readers and reader C.S. length, vary delay between updates
-#y: ops/s
-
-rm -f runall.log
-rm -fr runall.detail.log
-
-
-echo Executing batch RCU test
-
-DURATION=10
-BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
- 131072 262144"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f batch-rcu.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for BATCH_SIZE in ${BATCH_ARRAY}; do
- echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
- ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log
-done
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-NUM_CPUS=64
-
-#extra options, e.g. for setting affinity on even CPUs :
-EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-#stride 1
-#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-#stride 2
-#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-#stride 4
-#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-#stride 8
-#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-
-#Vary update fraction
-#x: vary update fraction from 0 to 0.0001
- #fix number of readers and reader C.S. length, vary delay between updates
-#y: ops/s
-
-rm -f runall.log
-rm -fr runall.detail.log
-
-#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT **
-EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
-
-echo Executing update fraction test
-
-DURATION=10
-WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
- 65536 131072 262144 524288 1048576 2097152 4194304 8388608
- 16777216 33554432 67108864 134217728"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f update-fraction.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for WDELAY in ${WDELAY_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log
-done
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-NUM_CPUS=64
-
-#extra options, e.g. for setting affinity on even CPUs :
-EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-#stride 1
-#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-#stride 2
-#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-#stride 4
-#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-#stride 8
-#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-
-#Vary update fraction
-#x: vary update fraction from 0 to 0.0001
- #fix number of readers and reader C.S. length, vary delay between updates
-#y: ops/s
-
-rm -f runall.log
-rm -fr runall.detail.log
-
-#setting gc each 32768. ** UPDATE FOR YOUR ARCHITECTURE BASED ON PHASE 1 RESULT **
-EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
-
-#Test scalability :
-# x: vary number of readers from 0 to num cpus
-# y: ops/s
-# 0 writer.
-
-echo Executing scalability test
-
-NR_WRITERS=0
-DURATION=10
-
-rm -f scalability.log
-
-for NR_READERS in $(seq 1 ${NUM_CPUS}); do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log
-done
-
-
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-export NUM_CPUS=8
-
-#extra options, e.g. for setting affinity on even CPUs :
-#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-rm -f *.log
-
-#stride 1
-export EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-sh subphase4.sh $*
-mkdir ppc64-8cores-stride1
-mv *.log ppc64-8cores-stride1/
-
-
-#stride 2
-export EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-sh subphase4.sh $*
-mkdir ppc64-8cores-stride2
-mv *.log ppc64-8cores-stride2/
-
-
-#stride 4
-export EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-sh subphase4.sh $*
-mkdir ppc64-8cores-stride4
-mv *.log ppc64-8cores-stride4/
-
-
-#stride 8
-export EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-sh subphase4.sh $*
-mkdir ppc64-8cores-stride8
-mv *.log ppc64-8cores-stride8/
+++ /dev/null
-# test run after write-size update
-
-sh runpaul-phase1.sh
-mkdir runpaul-phase1
-mv *.log runpaul-phase1/
-
-sh runpaul-phase2.sh
-mkdir runpaul-phase2
-mv *.log runpaul-phase2/
-
-sh runpaul-phase4.sh
+++ /dev/null
-sh runpaul-phase1.sh
-mkdir runpaul-phase1
-mv *.log runpaul-phase1/
-
-sh runpaul-phase2.sh
-mkdir runpaul-phase2
-mv *.log runpaul-phase2/
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-export NUM_CPUS=64
-#export NUM_CPUS=8
-
-#extra options, e.g. for setting affinity on even CPUs :
-EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-#EXTRA_OPTS=$(for a in $(seq 0 1 7); do echo -n "-a ${a} "; done)
-
-rm -f *.log
-
-# x: Vary writer C.S. length from 0 to 100 us
-# y: reads/s
-# 4 readers
-# 4 writers
-
-echo Executing writer C.S. length test
-
-NR_READERS=$((${NUM_CPUS} / 2))
-NR_WRITERS=$((${NUM_CPUS} / 2))
-DURATION=10
-WDELAY=10
-#in loops.
-WRITERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
-
-rm -f writercslen.log
-
-for WRITERCSLEN in ${WRITERCSLEN_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -d ${WDELAY} -e ${WRITERCSLEN} | tee -a writercslen.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -d ${WDELAY} -e ${WRITERCSLEN} | tee -a writercslen.log
-done
-
-
-
-mkdir ppc64-writercslen
-mv *.log ppc64-writercslen/
-#mkdir xeon-writercslen
-#mv *.log xeon-writercslen/
+++ /dev/null
-#!/bin/sh
-
-. ./common.sh
-
-log_file="runall.detail.log"
-
-# Check if time bin is non-empty
-if [ -n "$test_time_bin" ]; then
- time_command="$test_time_bin -a -o $log_file"
-else
- time_command=""
-fi
-
-#for a in test_urcu_gc test_urcu_gc_mb test_urcu_qsbr_gc; do
-for a in test_urcu_gc; do
- echo "./${a} $*" | tee -a "$log_file"
- $time_command ./${a} $*
-done
-
+++ /dev/null
-#!/bin/sh
-
-. ./common.sh
-
-log_file="runall.detail.log"
-
-# Check if time bin is non-empty
-if [ -n "$test_time_bin" ]; then
- time_command="$test_time_bin -a -o $log_file"
-else
- time_command=""
-fi
-
-for a in test_urcu_gc test_urcu_signal_gc test_urcu_mb_gc test_urcu_qsbr_gc \
- test_urcu_lgc test_urcu_signal_lgc test_urcu_mb_lgc test_urcu_qsbr_lgc \
- test_urcu test_urcu_signal test_urcu_mb test_urcu_qsbr \
- test_rwlock test_perthreadlock test_mutex; do
- echo "./${a} $*" | tee -a "$log_file"
- $time_command ./${a} $*
-done
-
+++ /dev/null
-#!/bin/sh
-
-#run all tests
-
-#set to number of active CPUS
-#NUM_CPUS=8
-
-#extra options, e.g. for setting affinity on even CPUs :
-#EXTRA_OPTS=$(for a in $(seq 0 2 127); do echo -n "-a ${a} "; done)
-
-#ppc64 striding, use with NUM_CPUS=8
-
-#stride 1
-#EXTRA_OPTS=$(for a in $(seq 0 2 15); do echo -n "-a ${a} "; done)
-#stride 2
-#EXTRA_OPTS=$(for a in $(seq 0 4 31); do echo -n "-a ${a} "; done)
-#stride 4
-#EXTRA_OPTS=$(for a in $(seq 0 8 63); do echo -n "-a ${a} "; done)
-#stride 8
-#EXTRA_OPTS=$(for a in $(seq 0 16 127); do echo -n "-a ${a} "; done)
-
-#Vary update fraction
-#x: vary update fraction from 0 to 0.0001
- #fix number of readers and reader C.S. length, vary delay between updates
-#y: ops/s
-
-rm -f runall.log
-rm -fr runall.detail.log
-
-
-echo Executing batch RCU test
-
-DURATION=10
-BATCH_ARRAY="1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536
- 131072 262144"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f batch-rcu.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for BATCH_SIZE in ${BATCH_ARRAY}; do
- echo "./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log" >> runall.log
- ./runtests-batch.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d 0 -b ${BATCH_SIZE} ${EXTRA_OPTS} | tee -a batch-rcu.log
-done
-
-#setting gc each 4096. ** UPDATE FOR YOUR ARCHITECTURE BASED ON TEST ABOVE **
-EXTRA_OPTS="${EXTRA_OPTS} -b 32768"
-
-echo Executing update fraction test
-
-DURATION=10
-WDELAY_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768
- 65536 131072 262144 524288 1048576 2097152 4194304 8388608
- 16777216 33554432 67108864 134217728"
-NR_WRITERS=$((${NUM_CPUS} / 2))
-
-rm -f update-fraction.log
-
-NR_READERS=$((${NUM_CPUS} - ${NR_WRITERS}))
-for WDELAY in ${WDELAY_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} -d ${WDELAY} ${EXTRA_OPTS} | tee -a update-fraction.log
-done
-
-#Test scalability :
-# x: vary number of readers from 0 to num cpus
-# y: ops/s
-# 0 writer.
-
-echo Executing scalability test
-
-NR_WRITERS=0
-DURATION=10
-
-rm -f scalability.log
-
-for NR_READERS in $(seq 1 ${NUM_CPUS}); do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS}| tee -a scalability.log
-done
-
-
-# x: Vary reader C.S. length from 0 to 100 us
-# y: ops/s
-# 8 readers
-# 0 writers
-
-echo Executing reader C.S. length test
-
-NR_READERS=${NUM_CPUS}
-NR_WRITERS=0
-DURATION=10
-#in loops.
-READERCSLEN_ARRAY="0 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152"
-
-rm -f readercslen.log
-
-for READERCSLEN in ${READERCSLEN_ARRAY}; do
- echo "./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log" >> runall.log
- ./runtests.sh ${NR_READERS} ${NR_WRITERS} ${DURATION} ${EXTRA_OPTS} -c ${READERCSLEN} | tee -a readercslen.log
-done
+++ /dev/null
-/*
- * test_cycles_per_loop.c
- *
- * Userspace RCU library - test cycles per loop
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <urcu/arch.h>
-#include <stdio.h>
-
-#define NR_LOOPS 1000000UL
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-int main()
-{
- cycles_t time1, time2;
-
- time1 = caa_get_cycles();
- loop_sleep(NR_LOOPS);
- time2 = caa_get_cycles();
- printf("CPU clock cycles per loop: %g\n", (time2 - time1) /
- (double)NR_LOOPS);
- return 0;
-}
+++ /dev/null
-/*
- * test_looplen.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <sched.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define debug_yield_read()
-#endif
-#include <urcu.h>
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-#define LOOPS 1048576
-#define TESTS 10
-
-int main(int argc, char **argv)
-{
- unsigned long i;
- cycles_t time1, time2;
- cycles_t time_tot = 0;
- double cpl;
-
- for (i = 0; i < TESTS; i++) {
- time1 = caa_get_cycles();
- loop_sleep(LOOPS);
- time2 = caa_get_cycles();
- time_tot += time2 - time1;
- }
- cpl = ((double)time_tot) / (double)TESTS / (double)LOOPS;
-
- printf("CALIBRATION : %g cycles per loop\n", cpl);
- printf("time_tot = %llu, LOOPS = %d, TESTS = %d\n",
- time_tot, LOOPS, TESTS);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-static pthread_mutex_t lock;
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static volatile struct test_array test_array = { 8 };
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_reads;
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *data)
-{
- unsigned long tidx = (unsigned long)data;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
-
- for (;;) {
- pthread_mutex_lock(&lock);
- assert(test_array.a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- pthread_mutex_unlock(&lock);
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- tot_nr_reads[tidx] = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *data)
-{
- unsigned long wtidx = (unsigned long)data;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- pthread_mutex_lock(&lock);
- test_array.a = 0;
- test_array.a = 8;
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- pthread_mutex_unlock(&lock);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
- cmm_smp_mb();
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- yield_active |= YIELD_READ;
- break;
- case 'w':
- yield_active |= YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
- tot_nr_reads = calloc(nr_readers, sizeof(*tot_nr_reads));
- tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += tot_nr_reads[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += tot_nr_writes[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
-
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- free(tot_nr_reads);
- free(tot_nr_writes);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-struct per_thread_lock {
- pthread_mutex_t lock;
-} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); /* cache-line aligned */
-
-static struct per_thread_lock *per_thread_lock;
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static volatile struct test_array test_array = { 8 };
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_reads;
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *data)
-{
- unsigned long tidx = (unsigned long)data;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
-
- for (;;) {
- pthread_mutex_lock(&per_thread_lock[tidx].lock);
- assert(test_array.a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- pthread_mutex_unlock(&per_thread_lock[tidx].lock);
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- tot_nr_reads[tidx] = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *data)
-{
- unsigned long wtidx = (unsigned long)data;
- long tidx;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- for (tidx = 0; tidx < nr_readers; tidx++) {
- pthread_mutex_lock(&per_thread_lock[tidx].lock);
- }
- test_array.a = 0;
- test_array.a = 8;
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- for (tidx = (long)nr_readers - 1; tidx >= 0; tidx--) {
- pthread_mutex_unlock(&per_thread_lock[tidx].lock);
- }
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
- cmm_smp_mb();
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- yield_active |= YIELD_READ;
- break;
- case 'w':
- yield_active |= YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- tot_nr_reads = calloc(nr_readers, sizeof(*tot_nr_reads));
- tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
- per_thread_lock = calloc(nr_readers, sizeof(*per_thread_lock));
- for (i = 0; i < nr_readers; i++) {
- err = pthread_mutex_init(&per_thread_lock[i].lock, NULL);
- if (err != 0)
- exit(1);
- }
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += tot_nr_reads[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += tot_nr_writes[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
-
- free(tid_reader);
- free(tid_writer);
- free(tot_nr_reads);
- free(tot_nr_writes);
- free(per_thread_lock);
- return 0;
-}
+++ /dev/null
-/*
- * test_perthreadloc_timing.c
- *
- * Per thread locks - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <pthread.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-
-#include "thread-id.h"
-
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-static struct test_array test_array = { 8 };
-
-struct per_thread_lock {
- pthread_mutex_t lock;
-} __attribute__((aligned(CAA_CACHE_LINE_SIZE))); /* cache-line aligned */
-
-static struct per_thread_lock *per_thread_lock;
-
-#define OUTER_READ_LOOP 200U
-#define INNER_READ_LOOP 100000U
-#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
-
-#define OUTER_WRITE_LOOP 10U
-#define INNER_WRITE_LOOP 200U
-#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
-
-static int num_read;
-static int num_write;
-
-#define NR_READ num_read
-#define NR_WRITE num_write
-
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
-
-void *thr_reader(void *arg)
-{
- int i, j;
- cycles_t time1, time2;
- long tidx = (long)arg;
-
- printf("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- sleep(2);
-
- time1 = caa_get_cycles();
- for (i = 0; i < OUTER_READ_LOOP; i++) {
- for (j = 0; j < INNER_READ_LOOP; j++) {
- pthread_mutex_lock(&per_thread_lock[tidx].lock);
- assert(test_array.a == 8);
- pthread_mutex_unlock(&per_thread_lock[tidx].lock);
- }
- }
- time2 = caa_get_cycles();
-
- reader_time[tidx] = time2 - time1;
-
- sleep(2);
- printf("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *arg)
-{
- int i, j;
- long tidx;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- sleep(2);
-
- for (i = 0; i < OUTER_WRITE_LOOP; i++) {
- for (j = 0; j < INNER_WRITE_LOOP; j++) {
- time1 = caa_get_cycles();
- for (tidx = 0; tidx < NR_READ; tidx++) {
- pthread_mutex_lock(&per_thread_lock[tidx].lock);
- }
- test_array.a = 8;
- for (tidx = NR_READ - 1; tidx >= 0; tidx--) {
- pthread_mutex_unlock(&per_thread_lock[tidx].lock);
- }
- time2 = caa_get_cycles();
- writer_time[(unsigned long)arg] += time2 - time1;
- usleep(1);
- }
- }
-
- printf("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- return ((void*)2);
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- int i;
- cycles_t tot_rtime = 0;
- cycles_t tot_wtime = 0;
-
- if (argc < 2) {
- printf("Usage : %s nr_readers nr_writers\n", argv[0]);
- exit(-1);
- }
- num_read = atoi(argv[1]);
- num_write = atoi(argv[2]);
-
- reader_time = calloc(num_read, sizeof(*reader_time));
- writer_time = calloc(num_write, sizeof(*writer_time));
- tid_reader = calloc(num_read, sizeof(*tid_reader));
- tid_writer = calloc(num_write, sizeof(*tid_writer));
-
- printf("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- per_thread_lock = malloc(sizeof(struct per_thread_lock) * NR_READ);
-
- for (i = 0; i < NR_READ; i++) {
- pthread_mutex_init(&per_thread_lock[i].lock, NULL);
- }
- for (i = 0; i < NR_READ; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- sleep(10);
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_rtime += reader_time[i];
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_wtime += writer_time[i];
- }
- printf("Time per read : %g cycles\n",
- (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
- printf("Time per write : %g cycles\n",
- (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
- free(per_thread_lock);
-
- free(reader_time);
- free(writer_time);
- free(tid_reader);
- free(tid_writer);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static volatile struct test_array test_array = { 8 };
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
-
- for (;;) {
- pthread_rwlock_rdlock(&lock);
- assert(test_array.a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- pthread_rwlock_unlock(&lock);
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- pthread_rwlock_wrlock(&lock);
- test_array.a = 0;
- test_array.a = 8;
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- pthread_rwlock_unlock(&lock);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- *count = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
- cmm_smp_mb();
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- yield_active |= YIELD_READ;
- break;
- case 'w':
- yield_active |= YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
-
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <pthread.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-
-#include "thread-id.h"
-
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER;
-
-static struct test_array test_array = { 8 };
-
-#define OUTER_READ_LOOP 200U
-#define INNER_READ_LOOP 100000U
-#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
-
-#define OUTER_WRITE_LOOP 10U
-#define INNER_WRITE_LOOP 200U
-#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
-
-static int num_read;
-static int num_write;
-
-#define NR_READ num_read
-#define NR_WRITE num_write
-
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
-
-void *thr_reader(void *arg)
-{
- int i, j;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- sleep(2);
-
- time1 = caa_get_cycles();
- for (i = 0; i < OUTER_READ_LOOP; i++) {
- for (j = 0; j < INNER_READ_LOOP; j++) {
- pthread_rwlock_rdlock(&lock);
- assert(test_array.a == 8);
- pthread_rwlock_unlock(&lock);
- }
- }
- time2 = caa_get_cycles();
-
- reader_time[(unsigned long)arg] = time2 - time1;
-
- sleep(2);
- printf("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *arg)
-{
- int i, j;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- sleep(2);
-
- for (i = 0; i < OUTER_WRITE_LOOP; i++) {
- for (j = 0; j < INNER_WRITE_LOOP; j++) {
- time1 = caa_get_cycles();
- pthread_rwlock_wrlock(&lock);
- test_array.a = 8;
- pthread_rwlock_unlock(&lock);
- time2 = caa_get_cycles();
- writer_time[(unsigned long)arg] += time2 - time1;
- usleep(1);
- }
- }
-
- printf("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- return ((void*)2);
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- int i;
- cycles_t tot_rtime = 0;
- cycles_t tot_wtime = 0;
-
- if (argc < 2) {
- printf("Usage : %s nr_readers nr_writers\n", argv[0]);
- exit(-1);
- }
- num_read = atoi(argv[1]);
- num_write = atoi(argv[2]);
-
- reader_time = calloc(num_read, sizeof(*reader_time));
- writer_time = calloc(num_write, sizeof(*writer_time));
- tid_reader = calloc(num_read, sizeof(*tid_reader));
- tid_writer = calloc(num_write, sizeof(*tid_writer));
-
- printf("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- sleep(10);
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_rtime += reader_time[i];
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_wtime += writer_time[i];
- }
- printf("Time per read : %g cycles\n",
- (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
- printf("Time per write : %g cycles\n",
- (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
-
- free(reader_time);
- free(writer_time);
- free(tid_reader);
- free(tid_writer);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_uatomic.c
- *
- * Userspace RCU library - test atomic operations
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <assert.h>
-#include <urcu/uatomic.h>
-
-struct testvals {
-#ifdef UATOMIC_HAS_ATOMIC_BYTE
- unsigned char c;
-#endif
-#ifdef UATOMIC_HAS_ATOMIC_SHORT
- unsigned short s;
-#endif
- unsigned int i;
- unsigned long l;
-};
-
-static struct testvals vals;
-
-#define do_test(ptr) \
-do { \
- __typeof__(*(ptr)) v; \
- \
- uatomic_add(ptr, 10); \
- assert(uatomic_read(ptr) == 10); \
- uatomic_add(ptr, -11UL); \
- assert(uatomic_read(ptr) == (__typeof__(*(ptr)))-1UL); \
- v = uatomic_cmpxchg(ptr, -1UL, 22); \
- assert(uatomic_read(ptr) == 22); \
- assert(v == (__typeof__(*(ptr)))-1UL); \
- v = uatomic_cmpxchg(ptr, 33, 44); \
- assert(uatomic_read(ptr) == 22); \
- assert(v == 22); \
- v = uatomic_xchg(ptr, 55); \
- assert(uatomic_read(ptr) == 55); \
- assert(v == 22); \
- uatomic_set(ptr, 22); \
- uatomic_inc(ptr); \
- assert(uatomic_read(ptr) == 23); \
- uatomic_dec(ptr); \
- assert(uatomic_read(ptr) == 22); \
- v = uatomic_add_return(ptr, 74); \
- assert(v == 96); \
- assert(uatomic_read(ptr) == 96); \
- uatomic_or(ptr, 58); \
- assert(uatomic_read(ptr) == 122); \
- v = uatomic_sub_return(ptr, 1); \
- assert(v == 121); \
- uatomic_sub(ptr, (unsigned int) 2); \
- assert(uatomic_read(ptr) == 119); \
- uatomic_inc(ptr); \
- uatomic_inc(ptr); \
- assert(uatomic_read(ptr) == 121); \
- uatomic_and(ptr, 129); \
- assert(uatomic_read(ptr) == 1); \
-} while (0)
-
-int main(int argc, char **argv)
-{
-#ifdef UATOMIC_HAS_ATOMIC_BYTE
- do_test(&vals.c);
-#endif
-#ifdef UATOMIC_HAS_ATOMIC_SHORT
- do_test(&vals.s);
-#endif
- do_test(&vals.i);
- do_test(&vals.l);
- printf("Atomic ops test OK\n");
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu.h>
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static int *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- int *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
- assert(!rcu_read_ongoing());
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- assert(rcu_read_ongoing());
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(*local_ptr == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- /* test extra thread registration */
- rcu_register_thread();
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *_count)
-{
- unsigned long long *count = _count;
- int *new, *old;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- new = malloc(sizeof(int));
- assert(new);
- *new = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- synchronize_rcu();
- if (old)
- *old = 0;
- free(old);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- *count = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
- free(test_rcu_pointer);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_assign.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static struct test_array *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-/*
- * malloc/free are reusing memory areas too quickly, which does not let us
- * test races appropriately. Use a large circular array for allocations.
- * ARRAY_SIZE is larger than nr_writers, and we keep the mutex across
- * both alloc and free, which insures we never run over our tail.
- */
-#define ARRAY_SIZE (1048576 * nr_writers)
-#define ARRAY_POISON 0xDEADBEEF
-static int array_index;
-static struct test_array *test_array;
-
-static struct test_array *test_array_alloc(void)
-{
- struct test_array *ret;
- int index;
-
- index = array_index % ARRAY_SIZE;
- assert(test_array[index].a == ARRAY_POISON ||
- test_array[index].a == 0);
- ret = &test_array[index];
- array_index++;
- if (array_index == ARRAY_SIZE)
- array_index = 0;
- return ret;
-}
-
-static void test_array_free(struct test_array *ptr)
-{
- if (!ptr)
- return;
- ptr->a = ARRAY_POISON;
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- struct test_array *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(local_ptr->a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *_count)
-{
- unsigned long long *count = _count;
- struct test_array *new, *old;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_copy_mutex_lock();
- new = test_array_alloc();
- new->a = 8;
- old = test_rcu_pointer;
- rcu_assign_pointer(test_rcu_pointer, new);
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- synchronize_rcu();
- if (old)
- old->a = 0;
- test_array_free(old);
- rcu_copy_mutex_unlock();
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- *count = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- test_array = calloc(1, sizeof(*test_array) * ARRAY_SIZE);
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
- test_array_free(test_rcu_pointer);
- free(test_array);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu-bp.h>
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static int *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- int *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
- assert(!rcu_read_ongoing());
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- assert(rcu_read_ongoing());
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(*local_ptr == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *_count)
-{
- unsigned long long *count = _count;
- int *new, *old;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- new = malloc(sizeof(int));
- *new = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- synchronize_rcu();
- if (old)
- *old = 0;
- free(old);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- *count = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
- free(test_rcu_pointer);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_defer.c
- *
- * Userspace RCU library - test program (with automatic reclamation)
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu.h>
-#include <urcu-defer.h>
-
-struct test_array {
- int a;
-};
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static struct test_array *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- struct test_array *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(local_ptr->a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-static void test_cb2(void *data)
-{
-}
-
-static void test_cb1(void *data)
-{
-}
-
-void *thr_writer(void *data)
-{
- unsigned long wtidx = (unsigned long)data;
- struct test_array *new, *old = NULL;
- int ret;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- ret = rcu_defer_register_thread();
- if (ret) {
- printf("Error in rcu_defer_register_thread\n");
- exit(-1);
- }
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- new = malloc(sizeof(*new));
- new->a = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- defer_rcu(free, old);
- defer_rcu(test_cb1, old);
- defer_rcu(test_cb1, (void *)-2L);
- defer_rcu(test_cb1, (void *)-2L);
- defer_rcu(test_cb1, old);
- defer_rcu(test_cb2, (void *)-2L);
- defer_rcu(test_cb2, (void *)-4L);
- defer_rcu(test_cb2, (void *)-2L);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- rcu_defer_unregister_thread();
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += tot_nr_writes[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(tot_nr_writes);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_fork.c
- *
- * Userspace RCU library - test program (fork)
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <sched.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_node {
- int somedata;
- struct rcu_head head;
-};
-
-static void cb(struct rcu_head *head)
-{
- struct test_node *node;
-
- fprintf(stderr, "rcu callback invoked in pid: %d\n",
- (int) getpid());
- node = caa_container_of(head, struct test_node, head);
- free(node);
-}
-
-static void test_rcu(void)
-{
- struct test_node *node;
-
- rcu_register_thread();
-
- synchronize_rcu();
-
- rcu_read_lock();
- rcu_read_unlock();
-
- node = malloc(sizeof(*node));
- assert(node);
-
- call_rcu(&node->head, cb);
-
- synchronize_rcu();
-
- rcu_unregister_thread();
-}
-
-int main(int argc, char **argv)
-{
- pid_t pid;
- int ret;
-
-#if 0
- /* pthread_atfork does not work with malloc/free in callbacks */
- ret = pthread_atfork(call_rcu_before_fork,
- call_rcu_after_fork_parent,
- call_rcu_after_fork_child);
- if (ret) {
- errno = ret;
- perror("pthread_atfork");
- exit(EXIT_FAILURE);
- }
-#endif
-
- test_rcu();
-
- synchronize_rcu();
-
- fprintf(stderr, "%s parent pid: %d, before fork\n",
- argv[0], (int) getpid());
-
- call_rcu_before_fork();
- pid = fork();
-
- if (pid == 0) {
- /* child */
- call_rcu_after_fork_child();
- fprintf(stderr, "%s child pid: %d, after fork\n",
- argv[0], (int) getpid());
- test_rcu();
- fprintf(stderr, "%s child pid: %d, after rcu test\n",
- argv[0], (int) getpid());
- } else if (pid > 0) {
- int status;
-
- /* parent */
- call_rcu_after_fork_parent();
- fprintf(stderr, "%s parent pid: %d, after fork\n",
- argv[0], (int) getpid());
- test_rcu();
- fprintf(stderr, "%s parent pid: %d, after rcu test\n",
- argv[0], (int) getpid());
- for (;;) {
- pid = wait(&status);
- if (WIFEXITED(status)) {
- fprintf(stderr, "child %u exited normally with status %u\n",
- pid, WEXITSTATUS(status));
- break;
- } else if (WIFSIGNALED(status)) {
- fprintf(stderr, "child %u was terminated by signal %u\n",
- pid, WTERMSIG(status));
- break;
- } else {
- continue;
- }
- }
- } else {
- perror("fork");
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
-}
+++ /dev/null
-/*
- * test_urcu_gc.c
- *
- * Userspace RCU library - test program (with batch reclamation)
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include <urcu.h>
-
-struct test_array {
- int a;
-};
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static struct test_array *test_rcu_pointer;
-
-static unsigned int reclaim_batch = 1;
-
-struct reclaim_queue {
- void **queue; /* Beginning of queue */
- void **head; /* Insert position */
-};
-
-static struct reclaim_queue *pending_reclaims;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- struct test_array *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(local_ptr->a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-static void rcu_gc_clear_queue(unsigned long wtidx)
-{
- void **p;
-
- /* Wait for Q.S and empty queue */
- synchronize_rcu();
-
- for (p = pending_reclaims[wtidx].queue;
- p < pending_reclaims[wtidx].head; p++) {
- /* poison */
- if (*p)
- ((struct test_array *)*p)->a = 0;
- free(*p);
- }
- pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue;
-}
-
-/* Using per-thread queue */
-static void rcu_gc_reclaim(unsigned long wtidx, void *old)
-{
- /* Queue pointer */
- *pending_reclaims[wtidx].head = old;
- pending_reclaims[wtidx].head++;
-
- if (caa_likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue
- < reclaim_batch))
- return;
-
- rcu_gc_clear_queue(wtidx);
-}
-
-void *thr_writer(void *data)
-{
- unsigned long wtidx = (unsigned long)data;
-#ifdef TEST_LOCAL_GC
- struct test_array *old = NULL;
-#else
- struct test_array *new, *old;
-#endif
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
-#ifndef TEST_LOCAL_GC
- new = malloc(sizeof(*new));
- new->a = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
-#endif
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- rcu_gc_reclaim(wtidx, old);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'b':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- reclaim_batch = atol(argv[++i]);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
- pending_reclaims = calloc(nr_writers, sizeof(*pending_reclaims));
- if (reclaim_batch * sizeof(*pending_reclaims[i].queue)
- < CAA_CACHE_LINE_SIZE)
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].queue = calloc(1, CAA_CACHE_LINE_SIZE);
- else
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].queue = calloc(reclaim_batch,
- sizeof(*pending_reclaims[i].queue));
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].head = pending_reclaims[i].queue;
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += tot_nr_writes[i];
- rcu_gc_clear_queue(i);
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
- "batch %u\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes, reclaim_batch);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(tot_nr_writes);
- for (i = 0; i < nr_writers; i++)
- free(pending_reclaims[i].queue);
- free(pending_reclaims);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_hash.c
- *
- * Userspace RCU library - test program
- *
- * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "test_urcu_hash.h"
-
-enum test_hash {
- TEST_HASH_RW,
- TEST_HASH_UNIQUE,
-};
-
-struct test_hash_cb {
- void (*sigusr1)(int signo);
- void (*sigusr2)(int signo);
- void *(*thr_reader)(void *_count);
- void *(*thr_writer)(void *_count);
- int (*populate_hash)(void);
-};
-
-static
-struct test_hash_cb test_hash_cb[] = {
- [TEST_HASH_RW] = {
- test_hash_rw_sigusr1_handler,
- test_hash_rw_sigusr2_handler,
- test_hash_rw_thr_reader,
- test_hash_rw_thr_writer,
- test_hash_rw_populate_hash,
- },
- [TEST_HASH_UNIQUE] = {
- test_hash_unique_sigusr1_handler,
- test_hash_unique_sigusr2_handler,
- test_hash_unique_thr_reader,
- test_hash_unique_thr_writer,
- test_hash_unique_populate_hash,
- },
-
-};
-
-static enum test_hash test_choice = TEST_HASH_RW;
-
-void (*get_sigusr1_cb(void))(int)
-{
- return test_hash_cb[test_choice].sigusr1;
-}
-
-void (*get_sigusr2_cb(void))(int)
-{
- return test_hash_cb[test_choice].sigusr2;
-}
-
-void *(*get_thr_reader_cb(void))(void *)
-{
- return test_hash_cb[test_choice].thr_reader;
-}
-
-void *(*get_thr_writer_cb(void))(void *)
-{
- return test_hash_cb[test_choice].thr_writer;
-}
-
-int (*get_populate_hash_cb(void))(void)
-{
- return test_hash_cb[test_choice].populate_hash;
-}
-
-DEFINE_URCU_TLS(unsigned int, rand_lookup);
-DEFINE_URCU_TLS(unsigned long, nr_add);
-DEFINE_URCU_TLS(unsigned long, nr_addexist);
-DEFINE_URCU_TLS(unsigned long, nr_del);
-DEFINE_URCU_TLS(unsigned long, nr_delnoent);
-DEFINE_URCU_TLS(unsigned long, lookup_fail);
-DEFINE_URCU_TLS(unsigned long, lookup_ok);
-
-struct cds_lfht *test_ht;
-
-volatile int test_go, test_stop;
-
-unsigned long wdelay;
-
-unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-unsigned long rduration;
-
-unsigned long init_hash_size = DEFAULT_HASH_SIZE;
-unsigned long min_hash_alloc_size = DEFAULT_MIN_ALLOC_SIZE;
-unsigned long max_hash_buckets_size = (1UL << 20);
-unsigned long init_populate;
-int opt_auto_resize;
-int add_only, add_unique, add_replace;
-const struct cds_lfht_mm_type *memory_backend;
-
-unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
-unsigned long init_pool_size = DEFAULT_RAND_POOL,
- lookup_pool_size = DEFAULT_RAND_POOL,
- write_pool_size = DEFAULT_RAND_POOL;
-int validate_lookup;
-unsigned long nr_hash_chains; /* 0: normal table, other: number of hash chains */
-
-int count_pipe[2];
-
-int verbose_mode;
-
-unsigned int cpu_affinities[NR_CPUS];
-unsigned int next_aff = 0;
-int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-DEFINE_URCU_TLS(unsigned long long, nr_writes);
-DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-unsigned int nr_readers;
-unsigned int nr_writers;
-
-static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-unsigned long test_compare(const void *key1, size_t key1_len,
- const void *key2, size_t key2_len)
-{
- if (caa_unlikely(key1_len != key2_len))
- return -1;
- assert(key1_len == sizeof(unsigned long));
- if (key1 == key2)
- return 0;
- else
- return 1;
-}
-
-void *thr_count(void *arg)
-{
- printf_verbose("thread_begin %s, tid %lu\n",
- "counter", urcu_get_thread_id());
-
- rcu_register_thread();
-
- for (;;) {
- unsigned long count;
- long approx_before, approx_after;
- ssize_t len;
- char buf[1];
-
- rcu_thread_offline();
- len = read(count_pipe[0], buf, 1);
- rcu_thread_online();
- if (caa_unlikely(!test_duration_read()))
- break;
- if (len != 1)
- continue;
- /* Accounting */
- printf("Counting nodes... ");
- fflush(stdout);
- rcu_read_lock();
- cds_lfht_count_nodes(test_ht, &approx_before, &count,
- &approx_after);
- rcu_read_unlock();
- printf("done.\n");
- printf("Approximation before node accounting: %ld nodes.\n",
- approx_before);
- printf("Accounting of nodes in the hash table: "
- "%lu nodes.\n",
- count);
- printf("Approximation after node accounting: %ld nodes.\n",
- approx_after);
- }
- rcu_unregister_thread();
- return NULL;
-}
-
-void free_node_cb(struct rcu_head *head)
-{
- struct lfht_test_node *node =
- caa_container_of(head, struct lfht_test_node, head);
- free(node);
-}
-
-static
-void test_delete_all_nodes(struct cds_lfht *ht)
-{
- struct cds_lfht_iter iter;
- struct lfht_test_node *node;
- unsigned long count = 0;
-
- cds_lfht_for_each_entry(ht, &iter, node, node) {
- int ret;
-
- ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
- assert(!ret);
- call_rcu(&node->head, free_node_cb);
- count++;
- }
- printf("deleted %lu nodes.\n", count);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf(" [-h size] (initial number of buckets)\n");
- printf(" [-m size] (minimum number of allocated buckets)\n");
- printf(" [-n size] (maximum number of buckets)\n");
-printf(" [not -u nor -s] Add entries (supports redundant keys).\n");
- printf(" [-u] Uniquify add (no redundant keys).\n");
- printf(" [-s] Replace (swap) entries.\n");
- printf(" [-i] Add only (no removal).\n");
- printf(" [-k nr_nodes] Number of nodes to insert initially.\n");
- printf(" [-A] Automatically resize hash table.\n");
- printf(" [-B order|chunk|mmap] Specify the memory backend.\n");
- printf(" [-R offset] Lookup pool offset.\n");
- printf(" [-S offset] Write pool offset.\n");
- printf(" [-T offset] Init pool offset.\n");
- printf(" [-M size] Lookup pool size.\n");
- printf(" [-N size] Write pool size.\n");
- printf(" [-O size] Init pool size.\n");
- printf(" [-V] Validate lookups of init values.\n");
- printf(" (use with filled init pool, same lookup range,\n");
- printf(" with different write range)\n");
- printf(" [-U] Uniqueness test.\n");
- printf(" [-C] Number of hash chains.\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- pthread_t *tid_reader, *tid_writer;
- pthread_t tid_count;
- void *tret;
- unsigned long long *count_reader;
- struct wr_count *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0,
- tot_add = 0, tot_add_exist = 0, tot_remove = 0;
- unsigned long count;
- long approx_before, approx_after;
- int i, a, ret, err, mainret = 0;
- struct sigaction act;
- unsigned int remain;
- unsigned int nr_readers_created = 0, nr_writers_created = 0;
- long long nr_leaked;
-
- if (argc < 4) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- yield_active |= YIELD_READ;
- break;
- case 'w':
- yield_active |= YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- case 'h':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- init_hash_size = atol(argv[++i]);
- break;
- case 'm':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- min_hash_alloc_size = atol(argv[++i]);
- break;
- case 'n':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- max_hash_buckets_size = atol(argv[++i]);
- break;
- case 'u':
- if (add_replace) {
- printf("Please specify at most one of -s or -u.\n");
- exit(-1);
- }
- add_unique = 1;
- break;
- case 's':
- if (add_unique) {
- printf("Please specify at most one of -s or -u.\n");
- exit(-1);
- }
- add_replace = 1;
- break;
- case 'i':
- add_only = 1;
- break;
- case 'k':
- init_populate = atol(argv[++i]);
- break;
- case 'A':
- opt_auto_resize = 1;
- break;
- case 'B':
- if (argc < i + 2) {
- show_usage(argc, argv);
- mainret = 1;
- goto end;
- }
- i++;
- if (!strcmp("order", argv[i]))
- memory_backend = &cds_lfht_mm_order;
- else if (!strcmp("chunk", argv[i]))
- memory_backend = &cds_lfht_mm_chunk;
- else if (!strcmp("mmap", argv[i]))
- memory_backend = &cds_lfht_mm_mmap;
- else {
- printf("Please specify memory backend with order|chunk|mmap.\n");
- mainret = 1;
- goto end;
- }
- break;
- case 'R':
- lookup_pool_offset = atol(argv[++i]);
- break;
- case 'S':
- write_pool_offset = atol(argv[++i]);
- break;
- case 'T':
- init_pool_offset = atol(argv[++i]);
- break;
- case 'M':
- lookup_pool_size = atol(argv[++i]);
- break;
- case 'N':
- write_pool_size = atol(argv[++i]);
- break;
- case 'O':
- init_pool_size = atol(argv[++i]);
- break;
- case 'V':
- validate_lookup = 1;
- break;
- case 'U':
- test_choice = TEST_HASH_UNIQUE;
- break;
- case 'C':
- nr_hash_chains = atol(argv[++i]);
- break;
- }
- }
-
- /* Check if hash size is power of 2 */
- if (init_hash_size && init_hash_size & (init_hash_size - 1)) {
- printf("Error: Initial number of buckets (%lu) is not a power of 2.\n",
- init_hash_size);
- mainret = 1;
- goto end;
- }
-
- if (min_hash_alloc_size && min_hash_alloc_size & (min_hash_alloc_size - 1)) {
- printf("Error: Minimum number of allocated buckets (%lu) is not a power of 2.\n",
- min_hash_alloc_size);
- mainret = 1;
- goto end;
- }
-
- if (max_hash_buckets_size && max_hash_buckets_size & (max_hash_buckets_size - 1)) {
- printf("Error: Maximum number of buckets (%lu) is not a power of 2.\n",
- max_hash_buckets_size);
- mainret = 1;
- goto end;
- }
-
- memset(&act, 0, sizeof(act));
- ret = sigemptyset(&act.sa_mask);
- if (ret == -1) {
- perror("sigemptyset");
- mainret = 1;
- goto end;
- }
- act.sa_handler = get_sigusr1_cb();
- act.sa_flags = SA_RESTART;
- ret = sigaction(SIGUSR1, &act, NULL);
- if (ret == -1) {
- perror("sigaction");
- mainret = 1;
- goto end;
- }
-
- act.sa_handler = get_sigusr2_cb();
- act.sa_flags = SA_RESTART;
- ret = sigaction(SIGUSR2, &act, NULL);
- if (ret == -1) {
- perror("sigaction");
- mainret = 1;
- goto end;
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("Mode:%s%s.\n",
- add_only ? " add only" : " add/remove",
- add_unique ? " uniquify" : ( add_replace ? " replace" : " insert"));
- printf_verbose("Initial number of buckets: %lu buckets.\n", init_hash_size);
- printf_verbose("Minimum number of allocated buckets: %lu buckets.\n", min_hash_alloc_size);
- printf_verbose("Maximum number of buckets: %lu buckets.\n", max_hash_buckets_size);
- printf_verbose("Init pool size offset %lu size %lu.\n",
- init_pool_offset, init_pool_size);
- printf_verbose("Lookup pool size offset %lu size %lu.\n",
- lookup_pool_offset, lookup_pool_size);
- printf_verbose("Update pool size offset %lu size %lu.\n",
- write_pool_offset, write_pool_size);
- printf_verbose("Number of hash chains: %lu.\n",
- nr_hash_chains);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- if (!tid_reader) {
- mainret = 1;
- goto end;
- }
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- if (!tid_writer) {
- mainret = 1;
- goto end_free_tid_reader;
- }
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- if (!count_reader) {
- mainret = 1;
- goto end_free_tid_writer;
- }
- count_writer = calloc(nr_writers, sizeof(*count_writer));
- if (!count_writer) {
- mainret = 1;
- goto end_free_count_reader;
- }
-
- err = create_all_cpu_call_rcu_data(0);
- if (err) {
- printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
- }
-
- if (memory_backend) {
- test_ht = _cds_lfht_new(init_hash_size, min_hash_alloc_size,
- max_hash_buckets_size,
- (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
- CDS_LFHT_ACCOUNTING, memory_backend,
- &rcu_flavor, NULL);
- } else {
- test_ht = cds_lfht_new(init_hash_size, min_hash_alloc_size,
- max_hash_buckets_size,
- (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
- CDS_LFHT_ACCOUNTING, NULL);
- }
- if (!test_ht) {
- printf("Error allocating hash table.\n");
- mainret = 1;
- goto end_free_call_rcu_data;
- }
-
- /*
- * Hash Population needs to be seen as a RCU reader
- * thread from the point of view of resize.
- */
- rcu_register_thread();
- ret = (get_populate_hash_cb())();
- assert(!ret);
-
- rcu_thread_offline();
-
- next_aff = 0;
-
- ret = pipe(count_pipe);
- if (ret == -1) {
- perror("pipe");
- mainret = 1;
- goto end_online;
- }
-
- /* spawn counter thread */
- err = pthread_create(&tid_count, NULL, thr_count,
- NULL);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_create");
- goto end_close_pipe;
- }
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i],
- NULL, get_thr_reader_cb(),
- &count_reader[i]);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_create");
- goto end_pthread_join;
- }
- nr_readers_created++;
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i],
- NULL, get_thr_writer_cb(),
- &count_writer[i]);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_create");
- goto end_pthread_join;
- }
- nr_writers_created++;
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- remain = duration;
- do {
- remain = sleep(remain);
- } while (remain > 0);
-
- test_stop = 1;
-
-end_pthread_join:
- for (i = 0; i < nr_readers_created; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_join");
- }
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers_created; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_join");
- }
- tot_writes += count_writer[i].update_ops;
- tot_add += count_writer[i].add;
- tot_add_exist += count_writer[i].add_exist;
- tot_remove += count_writer[i].remove;
- }
-
- /* teardown counter thread */
- act.sa_handler = SIG_IGN;
- act.sa_flags = SA_RESTART;
- ret = sigaction(SIGUSR2, &act, NULL);
- if (ret == -1) {
- mainret = 1;
- perror("sigaction");
- }
- {
- char msg[1] = { 0x42 };
- ssize_t ret;
-
- do {
- ret = write(count_pipe[1], msg, 1); /* wakeup thread */
- } while (ret == -1L && errno == EINTR);
- }
- err = pthread_join(tid_count, &tret);
- if (err != 0) {
- errno = err;
- mainret = 1;
- perror("pthread_join");
- }
-
-end_close_pipe:
- for (i = 0; i < 2; i++) {
- err = close(count_pipe[i]);
- if (err) {
- mainret = 1;
- perror("close pipe");
- }
- }
- fflush(stdout);
-end_online:
- rcu_thread_online();
- rcu_read_lock();
- printf("Counting nodes... ");
- cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
- printf("done.\n");
- test_delete_all_nodes(test_ht);
- rcu_read_unlock();
- rcu_thread_offline();
- if (count) {
- printf("Approximation before node accounting: %ld nodes.\n",
- approx_before);
- printf("Nodes deleted from hash table before destroy: "
- "%lu nodes.\n",
- count);
- printf("Approximation after node accounting: %ld nodes.\n",
- approx_after);
- }
-
- ret = cds_lfht_destroy(test_ht, NULL);
- if (ret) {
- printf_verbose("final delete aborted\n");
- mainret = 1;
- } else {
- printf_verbose("final delete success\n");
- }
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- nr_leaked = (long long) tot_add + init_populate - tot_remove - count;
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
- "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
- argv[0], duration, nr_readers, rduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
- nr_leaked);
- if (nr_leaked != 0) {
- mainret = 1;
- printf("WARNING: %lld nodes were leaked!\n", nr_leaked);
- }
-
- rcu_unregister_thread();
-end_free_call_rcu_data:
- free_all_cpu_call_rcu_data();
- free(count_writer);
-end_free_count_reader:
- free(count_reader);
-end_free_tid_writer:
- free(tid_writer);
-end_free_tid_reader:
- free(tid_reader);
-end:
- if (!mainret)
- exit(EXIT_SUCCESS);
- else
- exit(EXIT_FAILURE);
-}
+++ /dev/null
-#ifndef _TEST_URCU_HASH_H
-#define _TEST_URCU_HASH_H
-
-/*
- * test_urcu_hash.h
- *
- * Userspace RCU library - test program
- *
- * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-#define DEFAULT_HASH_SIZE 32
-#define DEFAULT_MIN_ALLOC_SIZE 1
-#define DEFAULT_RAND_POOL 1000000
-
-/*
- * Note: the hash seed should be a random value for hash tables
- * targeting production environments to provide protection against
- * denial of service attacks. We keep it a static value within this test
- * program to compare identical benchmark runs.
- */
-#define TEST_HASH_SEED 0x42UL
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifdef POISON_FREE
-#define poison_free(ptr) \
- do { \
- memset(ptr, 0x42, sizeof(*(ptr))); \
- free(ptr); \
- } while (0)
-#else
-#define poison_free(ptr) free(ptr)
-#endif
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define debug_yield_read()
-#endif
-#include <urcu-qsbr.h>
-#include <urcu/rculfhash.h>
-#include <urcu-call-rcu.h>
-
-struct wr_count {
- unsigned long update_ops;
- unsigned long add;
- unsigned long add_exist;
- unsigned long remove;
-};
-
-extern DECLARE_URCU_TLS(unsigned int, rand_lookup);
-extern DECLARE_URCU_TLS(unsigned long, nr_add);
-extern DECLARE_URCU_TLS(unsigned long, nr_addexist);
-extern DECLARE_URCU_TLS(unsigned long, nr_del);
-extern DECLARE_URCU_TLS(unsigned long, nr_delnoent);
-extern DECLARE_URCU_TLS(unsigned long, lookup_fail);
-extern DECLARE_URCU_TLS(unsigned long, lookup_ok);
-
-extern struct cds_lfht *test_ht;
-
-struct test_data {
- int a;
- int b;
-};
-
-struct lfht_test_node {
- struct cds_lfht_node node;
- void *key;
- unsigned int key_len;
- /* cache-cold for iteration */
- struct rcu_head head;
-};
-
-static inline struct lfht_test_node *
-to_test_node(struct cds_lfht_node *node)
-{
- return caa_container_of(node, struct lfht_test_node, node);
-}
-
-static inline
-void lfht_test_node_init(struct lfht_test_node *node, void *key,
- size_t key_len)
-{
- cds_lfht_node_init(&node->node);
- node->key = key;
- node->key_len = key_len;
-}
-
-static inline struct lfht_test_node *
-cds_lfht_iter_get_test_node(struct cds_lfht_iter *iter)
-{
- return to_test_node(cds_lfht_iter_get_node(iter));
-}
-
-extern volatile int test_go, test_stop;
-
-extern unsigned long wdelay;
-
-extern unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-extern unsigned long rduration;
-
-extern unsigned long init_hash_size;
-extern unsigned long min_hash_alloc_size;
-extern unsigned long max_hash_buckets_size;
-extern unsigned long init_populate;
-extern int opt_auto_resize;
-extern int add_only, add_unique, add_replace;
-extern const struct cds_lfht_mm_type *memory_backend;
-
-extern unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
-extern unsigned long init_pool_size,
- lookup_pool_size,
- write_pool_size;
-extern int validate_lookup;
-
-extern unsigned long nr_hash_chains;
-
-extern int count_pipe[2];
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-extern int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, ## args); \
- } while (0)
-
-extern unsigned int cpu_affinities[NR_CPUS];
-extern unsigned int next_aff;
-extern int use_affinity;
-
-extern pthread_mutex_t affinity_mutex;
-
-void set_affinity(void);
-
-/*
- * returns 0 if test should end.
- */
-static inline int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static inline int test_duration_read(void)
-{
- return !test_stop;
-}
-
-extern DECLARE_URCU_TLS(unsigned long long, nr_writes);
-extern DECLARE_URCU_TLS(unsigned long long, nr_reads);
-
-extern unsigned int nr_readers;
-extern unsigned int nr_writers;
-
-void rcu_copy_mutex_lock(void);
-void rcu_copy_mutex_unlock(void);
-
-/*
- * Hash function
- * Source: http://burtleburtle.net/bob/c/lookup3.c
- * Originally Public Domain
- */
-
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-
-#define mix(a, b, c) \
-do { \
- a -= c; a ^= rot(c, 4); c += b; \
- b -= a; b ^= rot(a, 6); a += c; \
- c -= b; c ^= rot(b, 8); b += a; \
- a -= c; a ^= rot(c, 16); c += b; \
- b -= a; b ^= rot(a, 19); a += c; \
- c -= b; c ^= rot(b, 4); b += a; \
-} while (0)
-
-#define final(a, b, c) \
-{ \
- c ^= b; c -= rot(b, 14); \
- a ^= c; a -= rot(c, 11); \
- b ^= a; b -= rot(a, 25); \
- c ^= b; c -= rot(b, 16); \
- a ^= c; a -= rot(c, 4);\
- b ^= a; b -= rot(a, 14); \
- c ^= b; c -= rot(b, 24); \
-}
-
-static inline __attribute__((unused))
-uint32_t hash_u32(
- const uint32_t *k, /* the key, an array of uint32_t values */
- size_t length, /* the length of the key, in uint32_ts */
- uint32_t initval) /* the previous hash, or an arbitrary value */
-{
- uint32_t a, b, c;
-
- /* Set up the internal state */
- a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
-
- /*----------------------------------------- handle most of the key */
- while (length > 3) {
- a += k[0];
- b += k[1];
- c += k[2];
- mix(a, b, c);
- length -= 3;
- k += 3;
- }
-
- /*----------------------------------- handle the last 3 uint32_t's */
- switch (length) { /* all the case statements fall through */
- case 3: c += k[2];
- case 2: b += k[1];
- case 1: a += k[0];
- final(a, b, c);
- case 0: /* case 0: nothing left to add */
- break;
- }
- /*---------------------------------------------- report the result */
- return c;
-}
-
-static inline
-void hashword2(
- const uint32_t *k, /* the key, an array of uint32_t values */
- size_t length, /* the length of the key, in uint32_ts */
- uint32_t *pc, /* IN: seed OUT: primary hash value */
- uint32_t *pb) /* IN: more seed OUT: secondary hash value */
-{
- uint32_t a, b, c;
-
- /* Set up the internal state */
- a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
- c += *pb;
-
- /*----------------------------------------- handle most of the key */
- while (length > 3) {
- a += k[0];
- b += k[1];
- c += k[2];
- mix(a, b, c);
- length -= 3;
- k += 3;
- }
-
- /*----------------------------------- handle the last 3 uint32_t's */
- switch (length) { /* all the case statements fall through */
- case 3: c += k[2];
- case 2: b += k[1];
- case 1: a += k[0];
- final(a, b, c);
- case 0: /* case 0: nothing left to add */
- break;
- }
- /*---------------------------------------------- report the result */
- *pc = c;
- *pb = b;
-}
-
-#if (CAA_BITS_PER_LONG == 32)
-static inline
-unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
-{
- unsigned int key = (unsigned int) _key;
-
- assert(length == sizeof(unsigned int));
- return hash_u32(&key, 1, seed);
-}
-#else
-static inline
-unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
-{
- union {
- uint64_t v64;
- uint32_t v32[2];
- } v;
- union {
- uint64_t v64;
- uint32_t v32[2];
- } key;
-
- assert(length == sizeof(unsigned long));
- v.v64 = (uint64_t) seed;
- key.v64 = (uint64_t) _key;
- hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
- return v.v64;
-}
-#endif
-
-/*
- * Hash function with nr_hash_chains != 0 for testing purpose only!
- * Creates very long hash chains, deteriorating the hash table into a
- * few linked lists, depending on the nr_hash_chains value. The purpose
- * of this test is to check how the hash table behaves with hash chains
- * containing different values, which is a rare case in a normal hash
- * table.
- */
-static inline
-unsigned long test_hash(const void *_key, size_t length,
- unsigned long seed)
-{
- if (nr_hash_chains == 0) {
- return test_hash_mix(_key, length, seed);
- } else {
- unsigned long v;
-
- assert(length == sizeof(unsigned long));
- v = (unsigned long) _key;
- return v % nr_hash_chains;
- }
-}
-
-unsigned long test_compare(const void *key1, size_t key1_len,
- const void *key2, size_t key2_len);
-
-static inline
-int test_match(struct cds_lfht_node *node, const void *key)
-{
- struct lfht_test_node *test_node = to_test_node(node);
-
- return !test_compare(test_node->key, test_node->key_len,
- key, sizeof(unsigned long));
-}
-
-static inline
-void cds_lfht_test_lookup(struct cds_lfht *ht, void *key, size_t key_len,
- struct cds_lfht_iter *iter)
-{
- assert(key_len == sizeof(unsigned long));
-
- cds_lfht_lookup(ht, test_hash(key, key_len, TEST_HASH_SEED),
- test_match, key, iter);
-}
-
-void free_node_cb(struct rcu_head *head);
-
-/* rw test */
-void test_hash_rw_sigusr1_handler(int signo);
-void test_hash_rw_sigusr2_handler(int signo);
-void *test_hash_rw_thr_reader(void *_count);
-void *test_hash_rw_thr_writer(void *_count);
-int test_hash_rw_populate_hash(void);
-
-/* unique test */
-void test_hash_unique_sigusr1_handler(int signo);
-void test_hash_unique_sigusr2_handler(int signo);
-void *test_hash_unique_thr_reader(void *_count);
-void *test_hash_unique_thr_writer(void *_count);
-int test_hash_unique_populate_hash(void);
-
-#endif /* _TEST_URCU_HASH_H */
+++ /dev/null
-/*
- * test_urcu_hash_rw.c
- *
- * Userspace RCU library - test program
- *
- * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "test_urcu_hash.h"
-
-enum urcu_hash_addremove {
- AR_RANDOM = 0,
- AR_ADD = 1,
- AR_REMOVE = -1,
-}; /* 1: add, -1 remove, 0: random */
-
-static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */
-
-void test_hash_rw_sigusr1_handler(int signo)
-{
- switch (addremove) {
- case AR_ADD:
- printf("Add/Remove: random.\n");
- addremove = AR_RANDOM;
- break;
- case AR_RANDOM:
- printf("Add/Remove: remove only.\n");
- addremove = AR_REMOVE;
- break;
- case AR_REMOVE:
- printf("Add/Remove: add only.\n");
- addremove = AR_ADD;
- break;
- }
-}
-
-void test_hash_rw_sigusr2_handler(int signo)
-{
- char msg[1] = { 0x42 };
- ssize_t ret;
-
- do {
- ret = write(count_pipe[1], msg, 1); /* wakeup thread */
- } while (ret == -1L && errno == EINTR);
-}
-
-void *test_hash_rw_thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- struct lfht_test_node *node;
- struct cds_lfht_iter iter;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- cds_lfht_test_lookup(test_ht,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset),
- sizeof(void *), &iter);
- node = cds_lfht_iter_get_test_node(&iter);
- if (node == NULL) {
- if (validate_lookup) {
- printf("[ERROR] Lookup cannot find initial node.\n");
- exit(-1);
- }
- URCU_TLS(lookup_fail)++;
- } else {
- URCU_TLS(lookup_ok)++;
- }
- rcu_debug_yield_read();
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
- rcu_quiescent_state();
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- printf_verbose("read tid : %lx, lookupfail %lu, lookupok %lu\n",
- urcu_get_thread_id(),
- URCU_TLS(lookup_fail),
- URCU_TLS(lookup_ok));
- return ((void*)1);
-
-}
-
-void *test_hash_rw_thr_writer(void *_count)
-{
- struct lfht_test_node *node;
- struct cds_lfht_node *ret_node;
- struct cds_lfht_iter iter;
- struct wr_count *count = _count;
- int ret;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- if ((addremove == AR_ADD || add_only)
- || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
- node = malloc(sizeof(struct lfht_test_node));
- lfht_test_node_init(node,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
- sizeof(void *));
- rcu_read_lock();
- if (add_unique) {
- ret_node = cds_lfht_add_unique(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- } else {
- if (add_replace)
- ret_node = cds_lfht_add_replace(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- else
- cds_lfht_add(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- &node->node);
- }
- rcu_read_unlock();
- if (add_unique && ret_node != &node->node) {
- free(node);
- URCU_TLS(nr_addexist)++;
- } else {
- if (add_replace && ret_node) {
- call_rcu(&to_test_node(ret_node)->head,
- free_node_cb);
- URCU_TLS(nr_addexist)++;
- } else {
- URCU_TLS(nr_add)++;
- }
- }
- } else {
- /* May delete */
- rcu_read_lock();
- cds_lfht_test_lookup(test_ht,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
- sizeof(void *), &iter);
- ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
- rcu_read_unlock();
- if (ret == 0) {
- node = cds_lfht_iter_get_test_node(&iter);
- call_rcu(&node->head, free_node_cb);
- URCU_TLS(nr_del)++;
- } else
- URCU_TLS(nr_delnoent)++;
- }
-#if 0
- //if (URCU_TLS(nr_writes) % 100000 == 0) {
- if (URCU_TLS(nr_writes) % 1000 == 0) {
- rcu_read_lock();
- if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
- ht_resize(test_ht, 1);
- } else {
- ht_resize(test_ht, -1);
- }
- rcu_read_unlock();
- }
-#endif //0
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
- rcu_quiescent_state();
- }
-
- rcu_unregister_thread();
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
- "nr_delnoent %lu\n", urcu_get_thread_id(),
- URCU_TLS(nr_add),
- URCU_TLS(nr_addexist),
- URCU_TLS(nr_del),
- URCU_TLS(nr_delnoent));
- count->update_ops = URCU_TLS(nr_writes);
- count->add = URCU_TLS(nr_add);
- count->add_exist = URCU_TLS(nr_addexist);
- count->remove = URCU_TLS(nr_del);
- return ((void*)2);
-}
-
-int test_hash_rw_populate_hash(void)
-{
- struct lfht_test_node *node;
- struct cds_lfht_node *ret_node;
-
- if (!init_populate)
- return 0;
-
- printf("Starting rw test\n");
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- if ((add_unique || add_replace) && init_populate * 10 > init_pool_size) {
- printf("WARNING: required to populate %lu nodes (-k), but random "
-"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
-"larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
- }
-
- while (URCU_TLS(nr_add) < init_populate) {
- node = malloc(sizeof(struct lfht_test_node));
- lfht_test_node_init(node,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
- sizeof(void *));
- rcu_read_lock();
- if (add_unique) {
- ret_node = cds_lfht_add_unique(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- } else {
- if (add_replace)
- ret_node = cds_lfht_add_replace(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- else
- cds_lfht_add(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- &node->node);
- }
- rcu_read_unlock();
- if (add_unique && ret_node != &node->node) {
- free(node);
- URCU_TLS(nr_addexist)++;
- } else {
- if (add_replace && ret_node) {
- call_rcu(&to_test_node(ret_node)->head, free_node_cb);
- URCU_TLS(nr_addexist)++;
- } else {
- URCU_TLS(nr_add)++;
- }
- }
- URCU_TLS(nr_writes)++;
- }
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_hash_unique.c
- *
- * Userspace RCU library - test program
- *
- * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "test_urcu_hash.h"
-
-enum urcu_hash_addremove {
- AR_RANDOM = 0,
- AR_ADD = 1,
- AR_REMOVE = -1,
-}; /* 1: add, -1 remove, 0: random */
-
-static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */
-
-void test_hash_unique_sigusr1_handler(int signo)
-{
- switch (addremove) {
- case AR_ADD:
- printf("Add/Remove: random.\n");
- addremove = AR_RANDOM;
- break;
- case AR_RANDOM:
- printf("Add/Remove: remove only.\n");
- addremove = AR_REMOVE;
- break;
- case AR_REMOVE:
- printf("Add/Remove: add only.\n");
- addremove = AR_ADD;
- break;
- }
-}
-
-void test_hash_unique_sigusr2_handler(int signo)
-{
- char msg[1] = { 0x42 };
- ssize_t ret;
-
- do {
- ret = write(count_pipe[1], msg, 1); /* wakeup thread */
- } while (ret == -1L && errno == EINTR);
-}
-
-void *test_hash_unique_thr_reader(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct lfht_test_node *node;
- struct cds_lfht_iter iter;
- /*
- * iterate on whole table, ensuring that no duplicate is
- * found.
- */
- rcu_read_lock();
- cds_lfht_for_each_entry(test_ht, &iter, node, node) {
- struct cds_lfht_iter dup_iter;
-
- dup_iter = iter;
- cds_lfht_next_duplicate(test_ht, test_match,
- node->key, &dup_iter);
- if (dup_iter.node != NULL) {
- printf("[ERROR] Duplicate key %p found\n", node->key);
- }
- }
- rcu_read_unlock();
-
- rcu_debug_yield_read();
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- URCU_TLS(nr_reads)++;
- if (caa_unlikely(!test_duration_read()))
- break;
- if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
- rcu_quiescent_state();
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- printf_verbose("read tid : %lu, lookupfail %lu, lookupok %lu\n",
- urcu_get_thread_id(), URCU_TLS(lookup_fail),
- URCU_TLS(lookup_ok));
- return ((void*)1);
-
-}
-
-void *test_hash_unique_thr_writer(void *_count)
-{
- struct lfht_test_node *node;
- struct cds_lfht_node *ret_node;
- struct cds_lfht_iter iter;
- struct wr_count *count = _count;
- int ret;
- int loc_add_unique;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- /*
- * add unique/add replace with new node key from range.
- */
- if (1 || (addremove == AR_ADD || add_only)
- || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
- node = malloc(sizeof(struct lfht_test_node));
- lfht_test_node_init(node,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
- sizeof(void *));
- rcu_read_lock();
- loc_add_unique = rand_r(&URCU_TLS(rand_lookup)) & 1;
- if (loc_add_unique) {
- ret_node = cds_lfht_add_unique(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- } else {
- ret_node = cds_lfht_add_replace(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
-#if 0 //generate an error on purpose
- cds_lfht_add(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- &node->node);
- ret_node = NULL;
-#endif //0
- }
- rcu_read_unlock();
- if (loc_add_unique) {
- if (ret_node != &node->node) {
- free(node);
- URCU_TLS(nr_addexist)++;
- } else {
- URCU_TLS(nr_add)++;
- }
- } else {
- if (ret_node) {
- call_rcu(&to_test_node(ret_node)->head,
- free_node_cb);
- URCU_TLS(nr_addexist)++;
- } else {
- URCU_TLS(nr_add)++;
- }
- }
- } else {
- /* May delete */
- rcu_read_lock();
- cds_lfht_test_lookup(test_ht,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
- sizeof(void *), &iter);
- ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
- rcu_read_unlock();
- if (ret == 0) {
- node = cds_lfht_iter_get_test_node(&iter);
- call_rcu(&node->head, free_node_cb);
- URCU_TLS(nr_del)++;
- } else
- URCU_TLS(nr_delnoent)++;
- }
-#if 0
- //if (URCU_TLS(nr_writes) % 100000 == 0) {
- if (URCU_TLS(nr_writes) % 1000 == 0) {
- rcu_read_lock();
- if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
- ht_resize(test_ht, 1);
- } else {
- ht_resize(test_ht, -1);
- }
- rcu_read_unlock();
- }
-#endif //0
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
- rcu_quiescent_state();
- }
-
- rcu_unregister_thread();
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
- "nr_delnoent %lu\n", urcu_get_thread_id(),
- URCU_TLS(nr_add),
- URCU_TLS(nr_addexist),
- URCU_TLS(nr_del),
- URCU_TLS(nr_delnoent));
- count->update_ops = URCU_TLS(nr_writes);
- count->add = URCU_TLS(nr_add);
- count->add_exist = URCU_TLS(nr_addexist);
- count->remove = URCU_TLS(nr_del);
- return ((void*)2);
-}
-
-int test_hash_unique_populate_hash(void)
-{
- struct lfht_test_node *node;
- struct cds_lfht_node *ret_node;
-
- printf("Starting uniqueness test.\n");
-
- URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
-
- if (!init_populate)
- return 0;
-
- if (init_populate * 10 > init_pool_size) {
- printf("WARNING: required to populate %lu nodes (-k), but random "
-"pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
-"larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
- }
-
- while (URCU_TLS(nr_add) < init_populate) {
- node = malloc(sizeof(struct lfht_test_node));
- lfht_test_node_init(node,
- (void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
- sizeof(void *));
- rcu_read_lock();
- ret_node = cds_lfht_add_replace(test_ht,
- test_hash(node->key, node->key_len, TEST_HASH_SEED),
- test_match, node->key, &node->node);
- rcu_read_unlock();
- if (ret_node) {
- call_rcu(&to_test_node(ret_node)->head, free_node_cb);
- URCU_TLS(nr_addexist)++;
- } else {
- URCU_TLS(nr_add)++;
- }
- URCU_TLS(nr_writes)++;
- }
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_lfq.c
- *
- * Userspace RCU library - example RCU-based lock-free queue
- *
- * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-#include <urcu.h>
-#include <urcu/cds.h>
-
-static volatile int test_go, test_stop;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-struct test {
- struct cds_lfq_node_rcu list;
- struct rcu_head rcu;
-};
-
-static struct cds_lfq_queue_rcu q;
-
-void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct test *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_lfq_node_init_rcu(&node->list);
- rcu_read_lock();
- cds_lfq_enqueue_rcu(&q, &node->list);
- rcu_read_unlock();
- URCU_TLS(nr_successful_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- rcu_unregister_thread();
-
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues));
- return ((void*)1);
-
-}
-
-static
-void free_node_cb(struct rcu_head *head)
-{
- struct test *node =
- caa_container_of(head, struct test, rcu);
- free(node);
-}
-
-void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_lfq_node_rcu *qnode;
-
- rcu_read_lock();
- qnode = cds_lfq_dequeue_rcu(&q);
- rcu_read_unlock();
-
- if (qnode) {
- struct test *node;
-
- node = caa_container_of(qnode, struct test, list);
- call_rcu(&node->rcu, free_node_cb);
- URCU_TLS(nr_successful_dequeues)++;
- }
-
- URCU_TLS(nr_dequeues)++;
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- rcu_unregister_thread();
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues),
- URCU_TLS(nr_successful_dequeues));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- return ((void*)2);
-}
-
-void test_end(struct cds_lfq_queue_rcu *q, unsigned long long *nr_dequeues)
-{
- struct cds_lfq_node_rcu *snode;
-
- do {
- snode = cds_lfq_dequeue_rcu(q);
- if (snode) {
- struct test *node;
-
- node = caa_container_of(snode, struct test, list);
- free(node); /* no more concurrent access */
- (*nr_dequeues)++;
- }
- } while (snode);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0;
- unsigned long long end_dequeues = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
- cds_lfq_init_rcu(&q, call_rcu);
- err = create_all_cpu_call_rcu_data(0);
- if (err) {
- printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
- }
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[2 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[2 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[2 * i];
- tot_successful_enqueues += count_enqueuer[2 * i + 1];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[2 * i];
- tot_successful_dequeues += count_dequeuer[2 * i + 1];
- }
-
- test_end(&q, &end_dequeues);
- err = cds_lfq_destroy_rcu(&q);
- assert(!err);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "successful dequeues %llu\n",
- tot_successful_enqueues, tot_successful_dequeues);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu successful dequeues %12llu "
- "end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_successful_dequeues, end_dequeues,
- tot_enqueues + tot_dequeues);
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
-
- free_all_cpu_call_rcu_data();
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_lfs.c
- *
- * Userspace RCU library - example lock-free stack
- *
- * Copyright 2010-2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-#include <urcu.h>
-#include <urcu/cds.h>
-
-/*
- * External synchronization used.
- */
-enum test_sync {
- TEST_SYNC_NONE = 0,
- TEST_SYNC_RCU,
-};
-
-static enum test_sync test_sync;
-
-static volatile int test_go, test_stop;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-static int test_pop, test_pop_all;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, ## args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-struct test {
- struct cds_lfs_node list;
- struct rcu_head rcu;
-};
-
-static struct cds_lfs_stack s;
-
-static void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct test *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_lfs_node_init(&node->list);
- cds_lfs_push(&s, &node->list);
- URCU_TLS(nr_successful_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- rcu_unregister_thread();
-
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues));
- return ((void*)1);
-
-}
-
-static
-void free_node_cb(struct rcu_head *head)
-{
- struct test *node =
- caa_container_of(head, struct test, rcu);
- free(node);
-}
-
-static
-void do_test_pop(enum test_sync sync)
-{
- struct cds_lfs_node *snode;
-
- if (sync == TEST_SYNC_RCU)
- rcu_read_lock();
- snode = __cds_lfs_pop(&s);
- if (sync == TEST_SYNC_RCU)
- rcu_read_unlock();
- if (snode) {
- struct test *node;
-
- node = caa_container_of(snode,
- struct test, list);
- if (sync == TEST_SYNC_RCU)
- call_rcu(&node->rcu, free_node_cb);
- else
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- }
- URCU_TLS(nr_dequeues)++;
-}
-
-static
-void do_test_pop_all(enum test_sync sync)
-{
- struct cds_lfs_node *snode;
- struct cds_lfs_head *head;
- struct cds_lfs_node *n;
-
- head = __cds_lfs_pop_all(&s);
- cds_lfs_for_each_safe(head, snode, n) {
- struct test *node;
-
- node = caa_container_of(snode, struct test, list);
- if (sync == TEST_SYNC_RCU)
- call_rcu(&node->rcu, free_node_cb);
- else
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- URCU_TLS(nr_dequeues)++;
- }
-
-}
-
-static void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
- unsigned int counter = 0;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- assert(test_pop || test_pop_all);
-
- for (;;) {
- if (test_pop && test_pop_all) {
- /* both pop and pop all */
- if (counter & 1)
- do_test_pop(test_sync);
- else
- do_test_pop_all(test_sync);
- counter++;
- } else {
- if (test_pop)
- do_test_pop(test_sync);
- else
- do_test_pop_all(test_sync);
- }
-
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- rcu_unregister_thread();
-
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues),
- URCU_TLS(nr_successful_dequeues));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- return ((void*)2);
-}
-
-static void test_end(struct cds_lfs_stack *s, unsigned long long *nr_dequeues)
-{
- struct cds_lfs_node *snode;
-
- do {
- snode = __cds_lfs_pop(s);
- if (snode) {
- struct test *node;
-
- node = caa_container_of(snode, struct test, list);
- free(node);
- (*nr_dequeues)++;
- }
- } while (snode);
-}
-
-static void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf(" [-p] (test pop)\n");
- printf(" [-P] (test pop_all, enabled by default)\n");
- printf(" [-R] (use RCU external synchronization)\n");
- printf(" Note: default: no external synchronization used.\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0;
- unsigned long long end_dequeues = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- case 'p':
- test_pop = 1;
- break;
- case 'P':
- test_pop_all = 1;
- break;
- case 'R':
- test_sync = TEST_SYNC_RCU;
- break;
- }
- }
-
- /* activate pop_all test by default */
- if (!test_pop && !test_pop_all)
- test_pop_all = 1;
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- if (test_pop)
- printf_verbose("pop test activated.\n");
- if (test_pop_all)
- printf_verbose("pop_all test activated.\n");
- if (test_sync == TEST_SYNC_RCU)
- printf_verbose("External sync: RCU.\n");
- else
- printf_verbose("External sync: none.\n");
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
- cds_lfs_init(&s);
- err = create_all_cpu_call_rcu_data(0);
- if (err) {
- printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
- }
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[2 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[2 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[2 * i];
- tot_successful_enqueues += count_enqueuer[2 * i + 1];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[2 * i];
- tot_successful_dequeues += count_dequeuer[2 * i + 1];
- }
-
- test_end(&s, &end_dequeues);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "successful dequeues %llu\n",
- tot_successful_enqueues, tot_successful_dequeues);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu successful dequeues %12llu "
- "end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_successful_dequeues, end_dequeues,
- tot_enqueues + tot_dequeues);
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
-
- free_all_cpu_call_rcu_data();
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_lfs_rcu.c
- *
- * Userspace RCU library - example RCU-based lock-free stack
- *
- * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-#include <urcu.h>
-
-/* Remove deprecation warnings from test build. */
-#define CDS_LFS_RCU_DEPRECATED
-
-#include <urcu/cds.h>
-
-static volatile int test_go, test_stop;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
- cpu_set_t mask;
- int cpu;
- int ret;
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-struct test {
- struct cds_lfs_node_rcu list;
- struct rcu_head rcu;
-};
-
-static struct cds_lfs_stack_rcu s;
-
-void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct test *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_lfs_node_init_rcu(&node->list);
- /* No rcu read-side is needed for push */
- cds_lfs_push_rcu(&s, &node->list);
- URCU_TLS(nr_successful_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- rcu_unregister_thread();
-
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues));
- return ((void*)1);
-
-}
-
-static
-void free_node_cb(struct rcu_head *head)
-{
- struct test *node =
- caa_container_of(head, struct test, rcu);
- free(node);
-}
-
-void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_lfs_node_rcu *snode;
-
- rcu_read_lock();
- snode = cds_lfs_pop_rcu(&s);
- rcu_read_unlock();
- if (snode) {
- struct test *node;
-
- node = caa_container_of(snode, struct test, list);
- call_rcu(&node->rcu, free_node_cb);
- URCU_TLS(nr_successful_dequeues)++;
- }
- URCU_TLS(nr_dequeues)++;
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- rcu_unregister_thread();
-
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues),
- URCU_TLS(nr_successful_dequeues));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- return ((void*)2);
-}
-
-void test_end(struct cds_lfs_stack_rcu *s, unsigned long long *nr_dequeues)
-{
- struct cds_lfs_node_rcu *snode;
-
- do {
- snode = cds_lfs_pop_rcu(s);
- if (snode) {
- struct test *node;
-
- node = caa_container_of(snode, struct test, list);
- free(node);
- (*nr_dequeues)++;
- }
- } while (snode);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0;
- unsigned long long end_dequeues = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
- cds_lfs_init_rcu(&s);
- err = create_all_cpu_call_rcu_data(0);
- if (err) {
- printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
- }
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[2 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[2 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[2 * i];
- tot_successful_enqueues += count_enqueuer[2 * i + 1];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[2 * i];
- tot_successful_dequeues += count_dequeuer[2 * i + 1];
- }
-
- test_end(&s, &end_dequeues);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "successful dequeues %llu\n",
- tot_successful_enqueues, tot_successful_dequeues);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu successful dequeues %12llu "
- "end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_successful_dequeues, end_dequeues,
- tot_enqueues + tot_dequeues);
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
-
- free_all_cpu_call_rcu_data();
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor-bp.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-#define RCU_SIGNAL
-#include <urcu-bp.h>
-#include "test_urcu_multiflavor.h"
-
-int test_mf_bp(void)
-{
- rcu_register_thread();
- rcu_read_lock();
- rcu_read_unlock();
- synchronize_rcu();
- rcu_unregister_thread();
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor-mb.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-#define RCU_MB
-#include <urcu.h>
-#include "test_urcu_multiflavor.h"
-
-int test_mf_mb(void)
-{
- rcu_register_thread();
- rcu_read_lock();
- rcu_read_unlock();
- synchronize_rcu();
- rcu_unregister_thread();
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor-memb.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-#include <urcu.h>
-#include "test_urcu_multiflavor.h"
-
-int test_mf_memb(void)
-{
- rcu_register_thread();
- rcu_read_lock();
- rcu_read_unlock();
- synchronize_rcu();
- rcu_unregister_thread();
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor-qsbr.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-#include <urcu-qsbr.h>
-#include "test_urcu_multiflavor.h"
-
-int test_mf_qsbr(void)
-{
- rcu_register_thread();
- rcu_read_lock();
- rcu_read_unlock();
- synchronize_rcu();
- rcu_unregister_thread();
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor-signal.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-#define RCU_SIGNAL
-#include <urcu.h>
-#include "test_urcu_multiflavor.h"
-
-int test_mf_signal(void)
-{
- rcu_register_thread();
- rcu_read_lock();
- rcu_read_unlock();
- synchronize_rcu();
- rcu_unregister_thread();
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor.c
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdlib.h>
-#include "test_urcu_multiflavor.h"
-
-int main(int argc, char **argv)
-{
- int ret;
-
- ret = test_mf_memb();
- if (ret)
- goto failure;
- ret = test_mf_mb();
- if (ret)
- goto failure;
- ret = test_mf_signal();
- if (ret)
- goto failure;
- ret = test_mf_qsbr();
- if (ret)
- goto failure;
- ret = test_mf_bp();
- if (ret)
- goto failure;
-
- exit(EXIT_SUCCESS);
-
-failure:
- exit(EXIT_FAILURE);
-}
+++ /dev/null
-/*
- * test_urcu_multiflavor.h
- *
- * Userspace RCU library - test multiple RCU flavors into one program
- *
- * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2012 - Lai Jiangshan <laijs@cn.fujitsu.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-extern int test_mf_memb(void);
-extern int test_mf_mb(void);
-extern int test_mf_signal(void);
-extern int test_mf_qsbr(void);
-extern int test_mf_bp(void);
-
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#else
-#define rcu_debug_yield_read()
-#endif
-#include "urcu-qsbr.h"
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static int *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- int *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- assert(rcu_read_ongoing());
- rcu_thread_offline();
- assert(!rcu_read_ongoing());
- rcu_thread_online();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- rcu_read_lock();
- assert(rcu_read_ongoing());
- local_ptr = rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(*local_ptr == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- /* QS each 1024 reads */
- if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
- rcu_quiescent_state();
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- /* test extra thread registration */
- rcu_register_thread();
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *_count)
-{
- unsigned long long *count = _count;
- int *new, *old;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- new = malloc(sizeof(int));
- assert(new);
- *new = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- synchronize_rcu();
- if (old)
- *old = 0;
- free(old);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- *count = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader, *count_writer;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- count_writer = calloc(nr_writers, sizeof(*count_writer));
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- &count_writer[i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += count_writer[i];
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes);
- free(test_rcu_pointer);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(count_writer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_gc.c
- *
- * Userspace RCU library - test program (with baatch reclamation)
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#define _LGPL_SOURCE
-#include <urcu-qsbr.h>
-
-struct test_array {
- int a;
-};
-
-static volatile int test_go, test_stop;
-
-static unsigned long wdelay;
-
-static struct test_array *test_rcu_pointer;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long rduration;
-static unsigned int reclaim_batch = 1;
-
-struct reclaim_queue {
- void **queue; /* Beginning of queue */
- void **head; /* Insert position */
-};
-
-static struct reclaim_queue *pending_reclaims;
-
-
-/* write-side C.S. duration, in loops */
-static unsigned long wduration;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_write(void)
-{
- return !test_stop;
-}
-
-static int test_duration_read(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_writes);
-static DEFINE_URCU_TLS(unsigned long long, nr_reads);
-
-static unsigned int nr_readers;
-static unsigned int nr_writers;
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-static
-unsigned long long __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *tot_nr_writes;
-
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-void *thr_reader(void *_count)
-{
- unsigned long long *count = _count;
- struct test_array *local_ptr;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
-
- set_affinity();
-
- rcu_register_thread();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- _rcu_read_lock();
- local_ptr = _rcu_dereference(test_rcu_pointer);
- rcu_debug_yield_read();
- if (local_ptr)
- assert(local_ptr->a == 8);
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- _rcu_read_unlock();
- URCU_TLS(nr_reads)++;
- /* QS each 1024 reads */
- if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
- _rcu_quiescent_state();
- if (caa_unlikely(!test_duration_read()))
- break;
- }
-
- rcu_unregister_thread();
-
- *count = URCU_TLS(nr_reads);
- printf_verbose("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-static void rcu_gc_clear_queue(unsigned long wtidx)
-{
- void **p;
-
- /* Wait for Q.S and empty queue */
- synchronize_rcu();
-
- for (p = pending_reclaims[wtidx].queue;
- p < pending_reclaims[wtidx].head; p++) {
- /* poison */
- if (*p)
- ((struct test_array *)*p)->a = 0;
- free(*p);
- }
- pending_reclaims[wtidx].head = pending_reclaims[wtidx].queue;
-}
-
-/* Using per-thread queue */
-static void rcu_gc_reclaim(unsigned long wtidx, void *old)
-{
- /* Queue pointer */
- *pending_reclaims[wtidx].head = old;
- pending_reclaims[wtidx].head++;
-
- if (caa_likely(pending_reclaims[wtidx].head - pending_reclaims[wtidx].queue
- < reclaim_batch))
- return;
-
- rcu_gc_clear_queue(wtidx);
-}
-
-void *thr_writer(void *data)
-{
- unsigned long wtidx = (unsigned long)data;
-#ifdef TEST_LOCAL_GC
- struct test_array *old = NULL;
-#else
- struct test_array *new, *old;
-#endif
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
-#ifndef TEST_LOCAL_GC
- new = malloc(sizeof(*new));
- new->a = 8;
- old = _rcu_xchg_pointer(&test_rcu_pointer, new);
-#endif
- if (caa_unlikely(wduration))
- loop_sleep(wduration);
- rcu_gc_reclaim(wtidx, old);
- URCU_TLS(nr_writes)++;
- if (caa_unlikely(!test_duration_write()))
- break;
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
- }
-
- printf_verbose("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- tot_nr_writes[wtidx] = URCU_TLS(nr_writes);
- return ((void*)2);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
-#ifdef DEBUG_YIELD
- printf(" [-r] [-w] (yield reader and/or writer)\n");
-#endif
- printf(" [-b batch] (batch reclaim)\n");
- printf(" [-d delay] (writer period (us))\n");
- printf(" [-c duration] (reader C.S. duration (in loops))\n");
- printf(" [-e duration] (writer C.S. duration (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- unsigned long long *count_reader;
- unsigned long long tot_reads = 0, tot_writes = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_readers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_writers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
-#ifdef DEBUG_YIELD
- case 'r':
- rcu_yield_active |= RCU_YIELD_READ;
- break;
- case 'w':
- rcu_yield_active |= RCU_YIELD_WRITE;
- break;
-#endif
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'b':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- reclaim_batch = atol(argv[++i]);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'e':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wduration = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
- duration, nr_readers, nr_writers);
- printf_verbose("Writer delay : %lu loops.\n", wdelay);
- printf_verbose("Reader duration : %lu loops.\n", rduration);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_reader = calloc(nr_readers, sizeof(*tid_reader));
- tid_writer = calloc(nr_writers, sizeof(*tid_writer));
- count_reader = calloc(nr_readers, sizeof(*count_reader));
- tot_nr_writes = calloc(nr_writers, sizeof(*tot_nr_writes));
- pending_reclaims = calloc(nr_writers, sizeof(*pending_reclaims));
- if (reclaim_batch * sizeof(*pending_reclaims[i].queue)
- < CAA_CACHE_LINE_SIZE)
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].queue = calloc(1, CAA_CACHE_LINE_SIZE);
- else
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].queue = calloc(reclaim_batch,
- sizeof(*pending_reclaims[i].queue));
- for (i = 0; i < nr_writers; i++)
- pending_reclaims[i].head = pending_reclaims[i].queue;
-
- next_aff = 0;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- &count_reader[i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- sleep(duration);
-
- test_stop = 1;
-
- for (i = 0; i < nr_readers; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_reads += count_reader[i];
- }
- for (i = 0; i < nr_writers; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_writes += tot_nr_writes[i];
- rcu_gc_clear_queue(i);
- }
-
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
- "batch %u\n",
- argv[0], duration, nr_readers, rduration, wduration,
- nr_writers, wdelay, tot_reads, tot_writes,
- tot_reads + tot_writes, reclaim_batch);
- free(tid_reader);
- free(tid_writer);
- free(count_reader);
- free(tot_nr_writes);
- for (i = 0; i < nr_writers; i++)
- free(pending_reclaims[i].queue);
- free(pending_reclaims);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_qsbr_timing.c
- *
- * Userspace QSBR - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include "thread-id.h"
-
-#define _LGPL_SOURCE
-#include <urcu-qsbr.h>
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-struct test_array {
- int a;
-};
-
-static struct test_array *test_rcu_pointer;
-
-#define OUTER_READ_LOOP 2000U
-#define INNER_READ_LOOP 100000U
-#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
-
-#define OUTER_WRITE_LOOP 10U
-#define INNER_WRITE_LOOP 200U
-#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
-
-static int num_read;
-static int num_write;
-
-#define NR_READ num_read
-#define NR_WRITE num_write
-
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
-
-void *thr_reader(void *arg)
-{
- int i, j;
- struct test_array *local_ptr;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- sleep(2);
-
- rcu_register_thread();
-
- time1 = caa_get_cycles();
- for (i = 0; i < OUTER_READ_LOOP; i++) {
- for (j = 0; j < INNER_READ_LOOP; j++) {
- _rcu_read_lock();
- local_ptr = _rcu_dereference(test_rcu_pointer);
- if (local_ptr) {
- assert(local_ptr->a == 8);
- }
- _rcu_read_unlock();
- }
- _rcu_quiescent_state();
- }
- time2 = caa_get_cycles();
-
- rcu_unregister_thread();
-
- reader_time[(unsigned long)arg] = time2 - time1;
-
- sleep(2);
- printf("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *arg)
-{
- int i, j;
- struct test_array *new, *old;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- sleep(2);
-
- for (i = 0; i < OUTER_WRITE_LOOP; i++) {
- for (j = 0; j < INNER_WRITE_LOOP; j++) {
- time1 = caa_get_cycles();
- new = malloc(sizeof(struct test_array));
- rcu_copy_mutex_lock();
- old = test_rcu_pointer;
- if (old) {
- assert(old->a == 8);
- }
- new->a = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- rcu_copy_mutex_unlock();
- synchronize_rcu();
- /* can be done after unlock */
- if (old) {
- old->a = 0;
- }
- free(old);
- time2 = caa_get_cycles();
- writer_time[(unsigned long)arg] += time2 - time1;
- usleep(1);
- }
- }
-
- printf("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- return ((void*)2);
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- int i;
- cycles_t tot_rtime = 0;
- cycles_t tot_wtime = 0;
-
- if (argc < 2) {
- printf("Usage : %s nr_readers nr_writers\n", argv[0]);
- exit(-1);
- }
- num_read = atoi(argv[1]);
- num_write = atoi(argv[2]);
-
- reader_time = calloc(num_read, sizeof(*reader_time));
- writer_time = calloc(num_write, sizeof(*writer_time));
- tid_reader = calloc(num_read, sizeof(*tid_reader));
- tid_writer = calloc(num_write, sizeof(*tid_writer));
-
- printf("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- sleep(10);
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_rtime += reader_time[i];
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_wtime += writer_time[i];
- }
- free(test_rcu_pointer);
- printf("Time per read : %g cycles\n",
- (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
- printf("Time per write : %g cycles\n",
- (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
-
- free(reader_time);
- free(writer_time);
- free(tid_reader);
- free(tid_writer);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu.c
- *
- * Userspace RCU library - test program
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-#include <urcu/arch.h>
-
-#include "thread-id.h"
-
-#define _LGPL_SOURCE
-#include <urcu.h>
-
-pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void rcu_copy_mutex_lock(void)
-{
- int ret;
- ret = pthread_mutex_lock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
-}
-
-void rcu_copy_mutex_unlock(void)
-{
- int ret;
-
- ret = pthread_mutex_unlock(&rcu_copy_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-}
-
-struct test_array {
- int a;
-};
-
-static struct test_array *test_rcu_pointer;
-
-#define OUTER_READ_LOOP 2000U
-#define INNER_READ_LOOP 100000U
-#define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP)
-
-#define OUTER_WRITE_LOOP 10U
-#define INNER_WRITE_LOOP 200U
-#define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP)
-
-static int num_read;
-static int num_write;
-
-#define NR_READ num_read
-#define NR_WRITE num_write
-
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time;
-static cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time;
-
-void *thr_reader(void *arg)
-{
- int i, j;
- struct test_array *local_ptr;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- sleep(2);
-
- rcu_register_thread();
-
- time1 = caa_get_cycles();
- for (i = 0; i < OUTER_READ_LOOP; i++) {
- for (j = 0; j < INNER_READ_LOOP; j++) {
- rcu_read_lock();
- local_ptr = rcu_dereference(test_rcu_pointer);
- if (local_ptr) {
- assert(local_ptr->a == 8);
- }
- rcu_read_unlock();
- }
- }
- time2 = caa_get_cycles();
-
- rcu_unregister_thread();
-
- reader_time[(unsigned long)arg] = time2 - time1;
-
- sleep(2);
- printf("thread_end %s, tid %lu\n",
- "reader", urcu_get_thread_id());
- return ((void*)1);
-
-}
-
-void *thr_writer(void *arg)
-{
- int i, j;
- struct test_array *new, *old;
- cycles_t time1, time2;
-
- printf("thread_begin %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- sleep(2);
-
- for (i = 0; i < OUTER_WRITE_LOOP; i++) {
- for (j = 0; j < INNER_WRITE_LOOP; j++) {
- time1 = caa_get_cycles();
- new = malloc(sizeof(struct test_array));
- rcu_copy_mutex_lock();
- old = test_rcu_pointer;
- if (old) {
- assert(old->a == 8);
- }
- new->a = 8;
- old = rcu_xchg_pointer(&test_rcu_pointer, new);
- rcu_copy_mutex_unlock();
- synchronize_rcu();
- /* can be done after unlock */
- if (old) {
- old->a = 0;
- }
- free(old);
- time2 = caa_get_cycles();
- writer_time[(unsigned long)arg] += time2 - time1;
- usleep(1);
- }
- }
-
- printf("thread_end %s, tid %lu\n",
- "writer", urcu_get_thread_id());
- return ((void*)2);
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_reader, *tid_writer;
- void *tret;
- int i;
- cycles_t tot_rtime = 0;
- cycles_t tot_wtime = 0;
-
- if (argc < 2) {
- printf("Usage : %s nr_readers nr_writers\n", argv[0]);
- exit(-1);
- }
- num_read = atoi(argv[1]);
- num_write = atoi(argv[2]);
-
- reader_time = calloc(num_read, sizeof(*reader_time));
- writer_time = calloc(num_write, sizeof(*writer_time));
- tid_reader = calloc(num_read, sizeof(*tid_reader));
- tid_writer = calloc(num_write, sizeof(*tid_writer));
-
- printf("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_create(&tid_reader[i], NULL, thr_reader,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_create(&tid_writer[i], NULL, thr_writer,
- (void *)(long)i);
- if (err != 0)
- exit(1);
- }
-
- sleep(10);
-
- for (i = 0; i < NR_READ; i++) {
- err = pthread_join(tid_reader[i], &tret);
- if (err != 0)
- exit(1);
- tot_rtime += reader_time[i];
- }
- for (i = 0; i < NR_WRITE; i++) {
- err = pthread_join(tid_writer[i], &tret);
- if (err != 0)
- exit(1);
- tot_wtime += writer_time[i];
- }
- free(test_rcu_pointer);
- printf("Time per read : %g cycles\n",
- (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP));
- printf("Time per write : %g cycles\n",
- (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP));
-
- free(reader_time);
- free(writer_time);
- free(tid_reader);
- free(tid_writer);
-
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_wfcq.c
- *
- * Userspace RCU library - example RCU-based lock-free concurrent queue
- *
- * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include <urcu/uatomic.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-#include <urcu/wfcqueue.h>
-
-enum test_sync {
- TEST_SYNC_NONE = 0,
- TEST_SYNC_MUTEX,
-};
-
-static enum test_sync test_sync;
-
-static int test_force_sync;
-
-static volatile int test_go, test_stop_enqueue, test_stop_dequeue;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-static int test_dequeue, test_splice, test_wait_empty;
-static int test_enqueue_stopped;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, ## args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop_dequeue;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop_enqueue;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-static DEFINE_URCU_TLS(unsigned long long, nr_empty_dest_enqueues);
-static DEFINE_URCU_TLS(unsigned long long, nr_splice);
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeue_last);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-static struct cds_wfcq_head __attribute__((aligned(CAA_CACHE_LINE_SIZE))) head;
-static struct cds_wfcq_tail __attribute__((aligned(CAA_CACHE_LINE_SIZE))) tail;
-
-static void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
- bool was_nonempty;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_wfcq_node *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_wfcq_node_init(node);
- was_nonempty = cds_wfcq_enqueue(&head, &tail, node);
- URCU_TLS(nr_successful_enqueues)++;
- if (!was_nonempty)
- URCU_TLS(nr_empty_dest_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- uatomic_inc(&test_enqueue_stopped);
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- count[2] = URCU_TLS(nr_empty_dest_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu, "
- "empty_dest_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues),
- URCU_TLS(nr_empty_dest_enqueues));
- return ((void*)1);
-
-}
-
-static void do_test_dequeue(enum test_sync sync)
-{
- struct cds_wfcq_node *node;
- int state;
-
- if (sync == TEST_SYNC_MUTEX)
- node = cds_wfcq_dequeue_with_state_blocking(&head, &tail,
- &state);
- else
- node = __cds_wfcq_dequeue_with_state_blocking(&head, &tail,
- &state);
-
- if (state & CDS_WFCQ_STATE_LAST)
- URCU_TLS(nr_dequeue_last)++;
-
- if (node) {
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- }
- URCU_TLS(nr_dequeues)++;
-}
-
-static void do_test_splice(enum test_sync sync)
-{
- struct cds_wfcq_head tmp_head;
- struct cds_wfcq_tail tmp_tail;
- struct cds_wfcq_node *node, *n;
- enum cds_wfcq_ret ret;
-
- cds_wfcq_init(&tmp_head, &tmp_tail);
-
- if (sync == TEST_SYNC_MUTEX)
- ret = cds_wfcq_splice_blocking(&tmp_head, &tmp_tail,
- &head, &tail);
- else
- ret = __cds_wfcq_splice_blocking(&tmp_head, &tmp_tail,
- &head, &tail);
-
- switch (ret) {
- case CDS_WFCQ_RET_WOULDBLOCK:
- assert(0); /* blocking call */
- break;
- case CDS_WFCQ_RET_DEST_EMPTY:
- URCU_TLS(nr_splice)++;
- URCU_TLS(nr_dequeue_last)++;
- /* ok */
- break;
- case CDS_WFCQ_RET_DEST_NON_EMPTY:
- assert(0); /* entirely unexpected */
- break;
- case CDS_WFCQ_RET_SRC_EMPTY:
- /* ok, we could even skip iteration on dest if we wanted */
- break;
- }
-
- __cds_wfcq_for_each_blocking_safe(&tmp_head, &tmp_tail, node, n) {
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- URCU_TLS(nr_dequeues)++;
- }
-}
-
-static void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
- unsigned int counter = 0;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- if (test_dequeue && test_splice) {
- if (counter & 1)
- do_test_dequeue(test_sync);
- else
- do_test_splice(test_sync);
- counter++;
- } else {
- if (test_dequeue)
- do_test_dequeue(test_sync);
- else
- do_test_splice(test_sync);
- }
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu, "
- "nr_splice %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
- URCU_TLS(nr_splice));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- count[2] = URCU_TLS(nr_splice);
- count[3] = URCU_TLS(nr_dequeue_last);
- return ((void*)2);
-}
-
-static void test_end(unsigned long long *nr_dequeues,
- unsigned long long *nr_dequeue_last)
-{
- struct cds_wfcq_node *node;
- int state;
-
- do {
- node = cds_wfcq_dequeue_with_state_blocking(&head, &tail,
- &state);
- if (node) {
- if (state & CDS_WFCQ_STATE_LAST)
- (*nr_dequeue_last)++;
- free(node);
- (*nr_dequeues)++;
- }
- } while (node);
-}
-
-static void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf(" [-q] (test dequeue)\n");
- printf(" [-s] (test splice, enabled by default)\n");
- printf(" [-M] (use mutex external synchronization)\n");
- printf(" Note: default: no external synchronization used.\n");
- printf(" [-f] (force user-provided synchronization)\n");
- printf(" [-w] Wait for dequeuer to empty queue\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0,
- tot_empty_dest_enqueues = 0,
- tot_splice = 0, tot_dequeue_last = 0;
- unsigned long long end_dequeues = 0;
- int i, a, retval = 0;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- case 'q':
- test_dequeue = 1;
- break;
- case 's':
- test_splice = 1;
- break;
- case 'M':
- test_sync = TEST_SYNC_MUTEX;
- break;
- case 'w':
- test_wait_empty = 1;
- break;
- case 'f':
- test_force_sync = 1;
- break;
- }
- }
-
- /* activate splice test by default */
- if (!test_dequeue && !test_splice)
- test_splice = 1;
-
- if (test_sync == TEST_SYNC_NONE && nr_dequeuers > 1 && test_dequeue) {
- if (test_force_sync) {
- fprintf(stderr, "[WARNING] Using dequeue concurrently "
- "with other dequeue or splice without external "
- "synchronization. Expect run-time failure.\n");
- } else {
- printf("Enforcing mutex synchronization\n");
- test_sync = TEST_SYNC_MUTEX;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- if (test_dequeue)
- printf_verbose("dequeue test activated.\n");
- else
- printf_verbose("splice test activated.\n");
- if (test_sync == TEST_SYNC_MUTEX)
- printf_verbose("External sync: mutex.\n");
- else
- printf_verbose("External sync: none.\n");
- if (test_wait_empty)
- printf_verbose("Wait for dequeuers to empty queue.\n");
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 3 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 4 * sizeof(*count_dequeuer));
- cds_wfcq_init(&head, &tail);
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[3 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[4 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop_enqueue = 1;
-
- if (test_wait_empty) {
- while (nr_enqueuers != uatomic_read(&test_enqueue_stopped)) {
- sleep(1);
- }
- while (!cds_wfcq_empty(&head, &tail)) {
- sleep(1);
- }
- }
-
- test_stop_dequeue = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[3 * i];
- tot_successful_enqueues += count_enqueuer[3 * i + 1];
- tot_empty_dest_enqueues += count_enqueuer[3 * i + 2];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[4 * i];
- tot_successful_dequeues += count_dequeuer[4 * i + 1];
- tot_splice += count_dequeuer[4 * i + 2];
- tot_dequeue_last += count_dequeuer[4 * i + 3];
- }
-
- test_end(&end_dequeues, &tot_dequeue_last);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "enqueues to empty dest : %llu, "
- "successful dequeues %llu, "
- "splice : %llu, dequeue_last : %llu\n",
- tot_successful_enqueues,
- tot_empty_dest_enqueues,
- tot_successful_dequeues,
- tot_splice, tot_dequeue_last);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu enqueues to empty dest %12llu "
- "successful dequeues %12llu splice %12llu "
- "dequeue_last %llu "
- "end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_empty_dest_enqueues,
- tot_successful_dequeues, tot_splice, tot_dequeue_last,
- end_dequeues,
- tot_enqueues + tot_dequeues);
-
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues) {
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
- retval = 1;
- }
-
- /*
- * If only using splice to dequeue, the enqueuer should see
- * exactly as many empty queues than the number of non-empty
- * src splice.
- */
- if (tot_empty_dest_enqueues != tot_dequeue_last) {
- printf("WARNING! Discrepancy between empty enqueue (%llu) and "
- "number of dequeue of last element (%llu)\n",
- tot_empty_dest_enqueues,
- tot_dequeue_last);
- retval = 1;
- }
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return retval;
-}
+++ /dev/null
-/*
- * test_urcu_wfq.c
- *
- * Userspace RCU library - example RCU-based lock-free queue
- *
- * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-
-/* Remove deprecation warnings from test build. */
-#define CDS_WFQ_DEPRECATED
-
-#include <urcu.h>
-#include <urcu/wfqueue.h>
-
-static volatile int test_go, test_stop;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-static struct cds_wfq_queue q;
-
-void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_wfq_node *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_wfq_node_init(node);
- cds_wfq_enqueue(&q, node);
- URCU_TLS(nr_successful_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues));
- return ((void*)1);
-
-}
-
-void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_wfq_node *node = cds_wfq_dequeue_blocking(&q);
-
- if (node) {
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- }
-
- URCU_TLS(nr_dequeues)++;
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues),
- URCU_TLS(nr_successful_dequeues));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- return ((void*)2);
-}
-
-void test_end(struct cds_wfq_queue *q, unsigned long long *nr_dequeues)
-{
- struct cds_wfq_node *node;
-
- do {
- node = cds_wfq_dequeue_blocking(q);
- if (node) {
- free(node);
- (*nr_dequeues)++;
- }
- } while (node);
-}
-
-void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0;
- unsigned long long end_dequeues = 0;
- int i, a;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 2 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 2 * sizeof(*count_dequeuer));
- cds_wfq_init(&q);
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[2 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[2 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[2 * i];
- tot_successful_enqueues += count_enqueuer[2 * i + 1];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[2 * i];
- tot_successful_dequeues += count_dequeuer[2 * i + 1];
- }
-
- test_end(&q, &end_dequeues);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "successful dequeues %llu\n",
- tot_successful_enqueues, tot_successful_dequeues);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu successful dequeues %12llu "
- "end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_successful_dequeues, end_dequeues,
- tot_enqueues + tot_dequeues);
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues)
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
-
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return 0;
-}
+++ /dev/null
-/*
- * test_urcu_wfs.c
- *
- * Userspace RCU library - example RCU-based lock-free stack
- *
- * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright February 2010 - Paolo Bonzini <pbonzini@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define _GNU_SOURCE
-#include "../config.h"
-#include <stdio.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <urcu/arch.h>
-#include <urcu/tls-compat.h>
-#include <urcu/uatomic.h>
-#include "cpuset.h"
-#include "thread-id.h"
-
-/* hardcoded number of CPUs */
-#define NR_CPUS 16384
-
-#ifndef DYNAMIC_LINK_TEST
-#define _LGPL_SOURCE
-#endif
-#include <urcu/wfstack.h>
-
-/*
- * External synchronization used.
- */
-enum test_sync {
- TEST_SYNC_NONE = 0,
- TEST_SYNC_MUTEX,
-};
-
-static enum test_sync test_sync;
-
-static int test_force_sync;
-
-static volatile int test_go, test_stop_enqueue, test_stop_dequeue;
-
-static unsigned long rduration;
-
-static unsigned long duration;
-
-/* read-side C.S. duration, in loops */
-static unsigned long wdelay;
-
-static inline void loop_sleep(unsigned long loops)
-{
- while (loops-- != 0)
- caa_cpu_relax();
-}
-
-static int verbose_mode;
-
-static int test_pop, test_pop_all, test_wait_empty;
-static int test_enqueue_stopped;
-
-#define printf_verbose(fmt, args...) \
- do { \
- if (verbose_mode) \
- printf(fmt, ## args); \
- } while (0)
-
-static unsigned int cpu_affinities[NR_CPUS];
-static unsigned int next_aff = 0;
-static int use_affinity = 0;
-
-pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void set_affinity(void)
-{
-#if HAVE_SCHED_SETAFFINITY
- cpu_set_t mask;
- int cpu, ret;
-#endif /* HAVE_SCHED_SETAFFINITY */
-
- if (!use_affinity)
- return;
-
-#if HAVE_SCHED_SETAFFINITY
- ret = pthread_mutex_lock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex lock");
- exit(-1);
- }
- cpu = cpu_affinities[next_aff++];
- ret = pthread_mutex_unlock(&affinity_mutex);
- if (ret) {
- perror("Error in pthread mutex unlock");
- exit(-1);
- }
-
- CPU_ZERO(&mask);
- CPU_SET(cpu, &mask);
-#if SCHED_SETAFFINITY_ARGS == 2
- sched_setaffinity(0, &mask);
-#else
- sched_setaffinity(0, sizeof(mask), &mask);
-#endif
-#endif /* HAVE_SCHED_SETAFFINITY */
-}
-
-/*
- * returns 0 if test should end.
- */
-static int test_duration_dequeue(void)
-{
- return !test_stop_dequeue;
-}
-
-static int test_duration_enqueue(void)
-{
- return !test_stop_enqueue;
-}
-
-static DEFINE_URCU_TLS(unsigned long long, nr_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_enqueues);
-
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_dequeues);
-static DEFINE_URCU_TLS(unsigned long long, nr_successful_enqueues);
-static DEFINE_URCU_TLS(unsigned long long, nr_empty_dest_enqueues);
-static DEFINE_URCU_TLS(unsigned long long, nr_pop_all);
-static DEFINE_URCU_TLS(unsigned long long, nr_pop_last);
-
-static unsigned int nr_enqueuers;
-static unsigned int nr_dequeuers;
-
-static struct cds_wfs_stack s;
-
-static void *thr_enqueuer(void *_count)
-{
- unsigned long long *count = _count;
- bool was_nonempty;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "enqueuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- for (;;) {
- struct cds_wfs_node *node = malloc(sizeof(*node));
- if (!node)
- goto fail;
- cds_wfs_node_init(node);
- was_nonempty = cds_wfs_push(&s, node);
- URCU_TLS(nr_successful_enqueues)++;
- if (!was_nonempty)
- URCU_TLS(nr_empty_dest_enqueues)++;
-
- if (caa_unlikely(wdelay))
- loop_sleep(wdelay);
-fail:
- URCU_TLS(nr_enqueues)++;
- if (caa_unlikely(!test_duration_enqueue()))
- break;
- }
-
- uatomic_inc(&test_enqueue_stopped);
- count[0] = URCU_TLS(nr_enqueues);
- count[1] = URCU_TLS(nr_successful_enqueues);
- count[2] = URCU_TLS(nr_empty_dest_enqueues);
- printf_verbose("enqueuer thread_end, tid %lu, "
- "enqueues %llu successful_enqueues %llu, "
- "empty_dest_enqueues %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_enqueues),
- URCU_TLS(nr_successful_enqueues),
- URCU_TLS(nr_empty_dest_enqueues));
- return ((void*)1);
-
-}
-
-static void do_test_pop(enum test_sync sync)
-{
- struct cds_wfs_node *node;
- int state;
-
- if (sync == TEST_SYNC_MUTEX)
- cds_wfs_pop_lock(&s);
- node = __cds_wfs_pop_with_state_blocking(&s, &state);
- if (sync == TEST_SYNC_MUTEX)
- cds_wfs_pop_unlock(&s);
-
- if (node) {
- if (state & CDS_WFS_STATE_LAST)
- URCU_TLS(nr_pop_last)++;
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- }
- URCU_TLS(nr_dequeues)++;
-}
-
-static void do_test_pop_all(enum test_sync sync)
-{
- struct cds_wfs_head *head;
- struct cds_wfs_node *node, *n;
-
- if (sync == TEST_SYNC_MUTEX)
- cds_wfs_pop_lock(&s);
- head = __cds_wfs_pop_all(&s);
- if (sync == TEST_SYNC_MUTEX)
- cds_wfs_pop_unlock(&s);
-
- /* Check if empty */
- if (cds_wfs_first(head) == NULL)
- return;
-
- URCU_TLS(nr_pop_all)++;
- URCU_TLS(nr_pop_last)++;
-
- cds_wfs_for_each_blocking_safe(head, node, n) {
- free(node);
- URCU_TLS(nr_successful_dequeues)++;
- URCU_TLS(nr_dequeues)++;
- }
-}
-
-static void *thr_dequeuer(void *_count)
-{
- unsigned long long *count = _count;
- unsigned int counter = 0;
-
- printf_verbose("thread_begin %s, tid %lu\n",
- "dequeuer", urcu_get_thread_id());
-
- set_affinity();
-
- while (!test_go)
- {
- }
- cmm_smp_mb();
-
- assert(test_pop || test_pop_all);
-
- for (;;) {
- if (test_pop && test_pop_all) {
- if (counter & 1)
- do_test_pop(test_sync);
- else
- do_test_pop_all(test_sync);
- counter++;
- } else {
- if (test_pop)
- do_test_pop(test_sync);
- else
- do_test_pop_all(test_sync);
- }
-
- if (caa_unlikely(!test_duration_dequeue()))
- break;
- if (caa_unlikely(rduration))
- loop_sleep(rduration);
- }
-
- printf_verbose("dequeuer thread_end, tid %lu, "
- "dequeues %llu, successful_dequeues %llu "
- "pop_all %llu pop_last %llu\n",
- urcu_get_thread_id(),
- URCU_TLS(nr_dequeues), URCU_TLS(nr_successful_dequeues),
- URCU_TLS(nr_pop_all),
- URCU_TLS(nr_pop_last));
- count[0] = URCU_TLS(nr_dequeues);
- count[1] = URCU_TLS(nr_successful_dequeues);
- count[2] = URCU_TLS(nr_pop_all);
- count[3] = URCU_TLS(nr_pop_last);
- return ((void*)2);
-}
-
-static void test_end(struct cds_wfs_stack *s, unsigned long long *nr_dequeues,
- unsigned long long *nr_pop_last)
-{
- struct cds_wfs_node *node;
- int state;
-
- do {
- node = cds_wfs_pop_with_state_blocking(s, &state);
- if (node) {
- if (state & CDS_WFS_STATE_LAST)
- (*nr_pop_last)++;
- free(node);
- (*nr_dequeues)++;
- }
- } while (node);
-}
-
-static void show_usage(int argc, char **argv)
-{
- printf("Usage : %s nr_dequeuers nr_enqueuers duration (s) <OPTIONS>\n",
- argv[0]);
- printf("OPTIONS:\n");
- printf(" [-d delay] (enqueuer period (in loops))\n");
- printf(" [-c duration] (dequeuer period (in loops))\n");
- printf(" [-v] (verbose output)\n");
- printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
- printf(" [-p] (test pop)\n");
- printf(" [-P] (test pop_all, enabled by default)\n");
- printf(" [-M] (use mutex external synchronization)\n");
- printf(" Note: default: no external synchronization used.\n");
- printf(" [-f] (force user-provided synchronization)\n");
- printf(" [-w] Wait for dequeuer to empty stack\n");
- printf("\n");
-}
-
-int main(int argc, char **argv)
-{
- int err;
- pthread_t *tid_enqueuer, *tid_dequeuer;
- void *tret;
- unsigned long long *count_enqueuer, *count_dequeuer;
- unsigned long long tot_enqueues = 0, tot_dequeues = 0;
- unsigned long long tot_successful_enqueues = 0,
- tot_successful_dequeues = 0,
- tot_empty_dest_enqueues = 0,
- tot_pop_all = 0, tot_pop_last = 0;
- unsigned long long end_dequeues = 0;
- int i, a, retval = 0;
-
- if (argc < 4) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[1], "%u", &nr_dequeuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[2], "%u", &nr_enqueuers);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- err = sscanf(argv[3], "%lu", &duration);
- if (err != 1) {
- show_usage(argc, argv);
- return -1;
- }
-
- for (i = 4; i < argc; i++) {
- if (argv[i][0] != '-')
- continue;
- switch (argv[i][1]) {
- case 'a':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- a = atoi(argv[++i]);
- cpu_affinities[next_aff++] = a;
- use_affinity = 1;
- printf_verbose("Adding CPU %d affinity\n", a);
- break;
- case 'c':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- rduration = atol(argv[++i]);
- break;
- case 'd':
- if (argc < i + 2) {
- show_usage(argc, argv);
- return -1;
- }
- wdelay = atol(argv[++i]);
- break;
- case 'v':
- verbose_mode = 1;
- break;
- case 'p':
- test_pop = 1;
- break;
- case 'P':
- test_pop_all = 1;
- break;
- case 'M':
- test_sync = TEST_SYNC_MUTEX;
- break;
- case 'w':
- test_wait_empty = 1;
- break;
- case 'f':
- test_force_sync = 1;
- break;
- }
- }
-
- /* activate pop_all test by default */
- if (!test_pop && !test_pop_all)
- test_pop_all = 1;
-
- if (test_sync == TEST_SYNC_NONE && nr_dequeuers > 1 && test_pop) {
- if (test_force_sync) {
- fprintf(stderr, "[WARNING] Using pop concurrently "
- "with other pop or pop_all without external "
- "synchronization. Expect run-time failure.\n");
- } else {
- printf("Enforcing mutex synchronization\n");
- test_sync = TEST_SYNC_MUTEX;
- }
- }
-
- printf_verbose("running test for %lu seconds, %u enqueuers, "
- "%u dequeuers.\n",
- duration, nr_enqueuers, nr_dequeuers);
- if (test_pop)
- printf_verbose("pop test activated.\n");
- if (test_pop_all)
- printf_verbose("pop_all test activated.\n");
- if (test_sync == TEST_SYNC_MUTEX)
- printf_verbose("External sync: mutex.\n");
- else
- printf_verbose("External sync: none.\n");
- if (test_wait_empty)
- printf_verbose("Wait for dequeuers to empty stack.\n");
- printf_verbose("Writer delay : %lu loops.\n", rduration);
- printf_verbose("Reader duration : %lu loops.\n", wdelay);
- printf_verbose("thread %-6s, tid %lu\n",
- "main", urcu_get_thread_id());
-
- tid_enqueuer = calloc(nr_enqueuers, sizeof(*tid_enqueuer));
- tid_dequeuer = calloc(nr_dequeuers, sizeof(*tid_dequeuer));
- count_enqueuer = calloc(nr_enqueuers, 3 * sizeof(*count_enqueuer));
- count_dequeuer = calloc(nr_dequeuers, 4 * sizeof(*count_dequeuer));
- cds_wfs_init(&s);
-
- next_aff = 0;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_create(&tid_enqueuer[i], NULL, thr_enqueuer,
- &count_enqueuer[3 * i]);
- if (err != 0)
- exit(1);
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_create(&tid_dequeuer[i], NULL, thr_dequeuer,
- &count_dequeuer[4 * i]);
- if (err != 0)
- exit(1);
- }
-
- cmm_smp_mb();
-
- test_go = 1;
-
- for (i = 0; i < duration; i++) {
- sleep(1);
- if (verbose_mode)
- write (1, ".", 1);
- }
-
- test_stop_enqueue = 1;
-
- if (test_wait_empty) {
- while (nr_enqueuers != uatomic_read(&test_enqueue_stopped)) {
- sleep(1);
- }
- while (!cds_wfs_empty(&s)) {
- sleep(1);
- }
- }
-
- test_stop_dequeue = 1;
-
- for (i = 0; i < nr_enqueuers; i++) {
- err = pthread_join(tid_enqueuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_enqueues += count_enqueuer[3 * i];
- tot_successful_enqueues += count_enqueuer[3 * i + 1];
- tot_empty_dest_enqueues += count_enqueuer[3 * i + 2];
- }
- for (i = 0; i < nr_dequeuers; i++) {
- err = pthread_join(tid_dequeuer[i], &tret);
- if (err != 0)
- exit(1);
- tot_dequeues += count_dequeuer[4 * i];
- tot_successful_dequeues += count_dequeuer[4 * i + 1];
- tot_pop_all += count_dequeuer[4 * i + 2];
- tot_pop_last += count_dequeuer[4 * i + 3];
- }
-
- test_end(&s, &end_dequeues, &tot_pop_last);
-
- printf_verbose("total number of enqueues : %llu, dequeues %llu\n",
- tot_enqueues, tot_dequeues);
- printf_verbose("total number of successful enqueues : %llu, "
- "enqueues to empty dest : %llu, "
- "successful dequeues %llu, "
- "pop_all : %llu, pop_last : %llu\n",
- tot_successful_enqueues,
- tot_empty_dest_enqueues,
- tot_successful_dequeues,
- tot_pop_all, tot_pop_last);
- printf("SUMMARY %-25s testdur %4lu nr_enqueuers %3u wdelay %6lu "
- "nr_dequeuers %3u "
- "rdur %6lu nr_enqueues %12llu nr_dequeues %12llu "
- "successful enqueues %12llu enqueues to empty dest %12llu "
- "successful dequeues %12llu pop_all %12llu "
- "pop_last %llu end_dequeues %llu nr_ops %12llu\n",
- argv[0], duration, nr_enqueuers, wdelay,
- nr_dequeuers, rduration, tot_enqueues, tot_dequeues,
- tot_successful_enqueues,
- tot_empty_dest_enqueues,
- tot_successful_dequeues, tot_pop_all, tot_pop_last,
- end_dequeues,
- tot_enqueues + tot_dequeues);
- if (tot_successful_enqueues != tot_successful_dequeues + end_dequeues) {
- printf("WARNING! Discrepancy between nr succ. enqueues %llu vs "
- "succ. dequeues + end dequeues %llu.\n",
- tot_successful_enqueues,
- tot_successful_dequeues + end_dequeues);
- retval = 1;
- }
- /*
- * The enqueuer should see exactly as many empty queues than the
- * number of non-empty stacks dequeued.
- */
- if (tot_empty_dest_enqueues != tot_pop_last) {
- printf("WARNING! Discrepancy between empty enqueue (%llu) and "
- "number of pop last (%llu)\n",
- tot_empty_dest_enqueues,
- tot_pop_last);
- retval = 1;
- }
- free(count_enqueuer);
- free(count_dequeuer);
- free(tid_enqueuer);
- free(tid_dequeuer);
- return retval;
-}
+++ /dev/null
-#ifndef _TEST_THREAD_ID_H
-#define _TEST_THREAD_ID_H
-
-/*
- * thread-id.h
- *
- * Userspace RCU library - thread ID
- *
- * Copyright 2013 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-
-#ifdef __linux__
-# include <syscall.h>
-
-# if defined(_syscall0)
-_syscall0(pid_t, gettid)
-# elif defined(__NR_gettid)
-static inline pid_t gettid(void)
-{
- return syscall(__NR_gettid);
-}
-# endif
-
-static inline
-unsigned long urcu_get_thread_id(void)
-{
- return (unsigned long) gettid();
-}
-#elif defined(__FreeBSD__)
-# include <pthread_np.h>
-
-static inline
-unsigned long urcu_get_thread_id(void)
-{
- return (unsigned long) pthread_getthreadid_np();
-}
-#else
-# warning "use pid as thread ID"
-static inline
-unsigned long urcu_get_thread_id(void)
-{
- return (unsigned long) getpid();
-}
-#endif
-
-#endif /* _TEST_THREAD_ID_H */
--- /dev/null
+AM_LDFLAGS=-lpthread
+AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g
+
+noinst_PROGRAMS = test_uatomic \
+ test_urcu_multiflavor \
+ test_urcu_multiflavor_dynlink
+
+noinst_HEADERS = test_urcu_multiflavor.h
+
+if COMPAT_ARCH
+COMPAT=$(top_srcdir)/compat_arch_@ARCHTYPE@.c
+else
+COMPAT=
+endif
+
+if COMPAT_FUTEX
+COMPAT+=$(top_srcdir)/compat_futex.c
+endif
+
+URCU=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_QSBR=$(top_srcdir)/urcu-qsbr.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_MB uses urcu.c but -DRCU_MB must be defined
+URCU_MB=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+# URCU_SIGNAL uses urcu.c but -DRCU_SIGNAL must be defined
+URCU_SIGNAL=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_BP=$(top_srcdir)/urcu-bp.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+URCU_DEFER=$(top_srcdir)/urcu.c $(top_srcdir)/urcu-pointer.c $(top_srcdir)/wfcqueue.c $(COMPAT)
+
+URCU_COMMON_LIB=$(top_builddir)/liburcu-common.la
+URCU_LIB=$(top_builddir)/liburcu.la
+URCU_QSBR_LIB=$(top_builddir)/liburcu-qsbr.la
+URCU_MB_LIB=$(top_builddir)/liburcu-mb.la
+URCU_SIGNAL_LIB=$(top_builddir)/liburcu-signal.la
+URCU_BP_LIB=$(top_builddir)/liburcu-bp.la
+URCU_CDS_LIB=$(top_builddir)/liburcu-cds.la
+
+test_uatomic_SOURCES = test_uatomic.c $(COMPAT)
+
+test_urcu_multiflavor_SOURCES = test_urcu_multiflavor.c \
+ test_urcu_multiflavor-memb.c \
+ test_urcu_multiflavor-mb.c \
+ test_urcu_multiflavor-signal.c \
+ test_urcu_multiflavor-qsbr.c \
+ test_urcu_multiflavor-bp.c
+test_urcu_multiflavor_LDADD = $(URCU_LIB) $(URCU_MB_LIB) \
+ $(URCU_SIGNAL_LIB) $(URCU_QSBR_LIB) $(URCU_BP_LIB)
+
+test_urcu_multiflavor_dynlink_SOURCES = test_urcu_multiflavor.c \
+ test_urcu_multiflavor-memb.c \
+ test_urcu_multiflavor-mb.c \
+ test_urcu_multiflavor-signal.c \
+ test_urcu_multiflavor-qsbr.c \
+ test_urcu_multiflavor-bp.c
+test_urcu_multiflavor_dynlink_CFLAGS = -DDYNAMIC_LINK_TEST $(AM_CFLAGS)
+test_urcu_multiflavor_dynlink_LDADD = $(URCU_LIB) $(URCU_MB_LIB) \
+ $(URCU_SIGNAL_LIB) $(URCU_QSBR_LIB) $(URCU_BP_LIB)
+
+check-am:
+ ./test_uatomic
+ ./test_urcu_multiflavor
+ ./test_urcu_multiflavor_dynlink
--- /dev/null
+/*
+ * test_uatomic.c
+ *
+ * Userspace RCU library - test atomic operations
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <urcu/uatomic.h>
+
+struct testvals {
+#ifdef UATOMIC_HAS_ATOMIC_BYTE
+ unsigned char c;
+#endif
+#ifdef UATOMIC_HAS_ATOMIC_SHORT
+ unsigned short s;
+#endif
+ unsigned int i;
+ unsigned long l;
+};
+
+static struct testvals vals;
+
+#define do_test(ptr) \
+do { \
+ __typeof__(*(ptr)) v; \
+ \
+ uatomic_add(ptr, 10); \
+ assert(uatomic_read(ptr) == 10); \
+ uatomic_add(ptr, -11UL); \
+ assert(uatomic_read(ptr) == (__typeof__(*(ptr)))-1UL); \
+ v = uatomic_cmpxchg(ptr, -1UL, 22); \
+ assert(uatomic_read(ptr) == 22); \
+ assert(v == (__typeof__(*(ptr)))-1UL); \
+ v = uatomic_cmpxchg(ptr, 33, 44); \
+ assert(uatomic_read(ptr) == 22); \
+ assert(v == 22); \
+ v = uatomic_xchg(ptr, 55); \
+ assert(uatomic_read(ptr) == 55); \
+ assert(v == 22); \
+ uatomic_set(ptr, 22); \
+ uatomic_inc(ptr); \
+ assert(uatomic_read(ptr) == 23); \
+ uatomic_dec(ptr); \
+ assert(uatomic_read(ptr) == 22); \
+ v = uatomic_add_return(ptr, 74); \
+ assert(v == 96); \
+ assert(uatomic_read(ptr) == 96); \
+ uatomic_or(ptr, 58); \
+ assert(uatomic_read(ptr) == 122); \
+ v = uatomic_sub_return(ptr, 1); \
+ assert(v == 121); \
+ uatomic_sub(ptr, (unsigned int) 2); \
+ assert(uatomic_read(ptr) == 119); \
+ uatomic_inc(ptr); \
+ uatomic_inc(ptr); \
+ assert(uatomic_read(ptr) == 121); \
+ uatomic_and(ptr, 129); \
+ assert(uatomic_read(ptr) == 1); \
+} while (0)
+
+int main(int argc, char **argv)
+{
+#ifdef UATOMIC_HAS_ATOMIC_BYTE
+ do_test(&vals.c);
+#endif
+#ifdef UATOMIC_HAS_ATOMIC_SHORT
+ do_test(&vals.s);
+#endif
+ do_test(&vals.i);
+ do_test(&vals.l);
+ printf("Atomic ops test OK\n");
+
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor-bp.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+#define RCU_SIGNAL
+#include <urcu-bp.h>
+#include "test_urcu_multiflavor.h"
+
+int test_mf_bp(void)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+ rcu_read_unlock();
+ synchronize_rcu();
+ rcu_unregister_thread();
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor-mb.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+#define RCU_MB
+#include <urcu.h>
+#include "test_urcu_multiflavor.h"
+
+int test_mf_mb(void)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+ rcu_read_unlock();
+ synchronize_rcu();
+ rcu_unregister_thread();
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor-memb.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+#include <urcu.h>
+#include "test_urcu_multiflavor.h"
+
+int test_mf_memb(void)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+ rcu_read_unlock();
+ synchronize_rcu();
+ rcu_unregister_thread();
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor-qsbr.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+#include <urcu-qsbr.h>
+#include "test_urcu_multiflavor.h"
+
+int test_mf_qsbr(void)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+ rcu_read_unlock();
+ synchronize_rcu();
+ rcu_unregister_thread();
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor-signal.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DYNAMIC_LINK_TEST
+#define _LGPL_SOURCE
+#endif
+
+#define RCU_SIGNAL
+#include <urcu.h>
+#include "test_urcu_multiflavor.h"
+
+int test_mf_signal(void)
+{
+ rcu_register_thread();
+ rcu_read_lock();
+ rcu_read_unlock();
+ synchronize_rcu();
+ rcu_unregister_thread();
+ return 0;
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor.c
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include "test_urcu_multiflavor.h"
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ ret = test_mf_memb();
+ if (ret)
+ goto failure;
+ ret = test_mf_mb();
+ if (ret)
+ goto failure;
+ ret = test_mf_signal();
+ if (ret)
+ goto failure;
+ ret = test_mf_qsbr();
+ if (ret)
+ goto failure;
+ ret = test_mf_bp();
+ if (ret)
+ goto failure;
+
+ exit(EXIT_SUCCESS);
+
+failure:
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * test_urcu_multiflavor.h
+ *
+ * Userspace RCU library - test multiple RCU flavors into one program
+ *
+ * Copyright February 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright February 2012 - Lai Jiangshan <laijs@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+extern int test_mf_memb(void);
+extern int test_mf_mb(void);
+extern int test_mf_signal(void);
+extern int test_mf_qsbr(void);
+extern int test_mf_bp(void);
+
--- /dev/null
+/*
+ * urcu-asm.c
+ *
+ * Userspace RCU library - assembly dump of primitives
+ *
+ * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <urcu.h>
+
+void show_read_lock(void)
+{
+ asm volatile ("/* start */");
+ rcu_read_lock();
+ asm volatile ("/* end */");
+}
+
+void show_read_unlock(void)
+{
+ asm volatile ("/* start */");
+ rcu_read_unlock();
+ asm volatile ("/* end */");
+}
+++ /dev/null
-/*
- * urcu-asm.c
- *
- * Userspace RCU library - assembly dump of primitives
- *
- * Copyright February 2009 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <urcu.h>
-
-void show_read_lock(void)
-{
- asm volatile ("/* start */");
- rcu_read_lock();
- asm volatile ("/* end */");
-}
-
-void show_read_unlock(void)
-{
- asm volatile ("/* start */");
- rcu_read_unlock();
- asm volatile ("/* end */");
-}
+++ /dev/null
-#define _GNU_SOURCE
-#include <string.h>
-#include <sys/time.h>
-#include <poll.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <urcu/arch.h>
-#include "api.h"
-#define _LGPL_SOURCE
-
-#ifdef RCU_MEMBARRIER
-#include <urcu.h>
-#endif
-#ifdef RCU_SIGNAL
-#include <urcu.h>
-#endif
-#ifdef RCU_MB
-#include <urcu.h>
-#endif
-#ifdef RCU_QSBR
-#include <urcu-qsbr.h>
-#endif
-#ifdef RCU_BP
-#include <urcu-bp.h>
-#endif
-
-#include <urcu/uatomic.h>
-#include <urcu/rculist.h>
-#include "rcutorture.h"