tests: split in check, regtest and bench targets
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 9 Aug 2013 22:13:23 +0000 (18:13 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Fri, 9 Aug 2013 22:36:26 +0000 (18:36 -0400)
Allow make check to run without requiring build machines to use hours of
CPU time.

make check: short unit tests
make regtest: long regression tests
make bench: long benchmarks

Fixes #611

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
115 files changed:
.gitignore
Makefile.am
configure.ac
tests/Makefile.am
tests/api.h [deleted file]
tests/benchmark/Makefile.am [new file with mode: 0644]
tests/benchmark/common.sh [new file with mode: 0644]
tests/benchmark/runall.sh [new file with mode: 0755]
tests/benchmark/runhash.sh [new file with mode: 0755]
tests/benchmark/runpaul-phase1.sh [new file with mode: 0755]
tests/benchmark/runpaul-phase2.sh [new file with mode: 0755]
tests/benchmark/runpaul-phase3.sh [new file with mode: 0755]
tests/benchmark/runpaul-phase4.sh [new file with mode: 0755]
tests/benchmark/runpaul-phase5.sh [new file with mode: 0644]
tests/benchmark/runpaul-phase6.sh [new file with mode: 0644]
tests/benchmark/runpaul-phase7.sh [new file with mode: 0755]
tests/benchmark/runtests-batch.sh [new file with mode: 0755]
tests/benchmark/runtests.sh [new file with mode: 0755]
tests/benchmark/subphase4.sh [new file with mode: 0755]
tests/benchmark/test_cycles_per_loop.c [new file with mode: 0644]
tests/benchmark/test_looplen.c [new file with mode: 0644]
tests/benchmark/test_mutex.c [new file with mode: 0644]
tests/benchmark/test_perthreadlock.c [new file with mode: 0644]
tests/benchmark/test_perthreadlock_timing.c [new file with mode: 0644]
tests/benchmark/test_rwlock.c [new file with mode: 0644]
tests/benchmark/test_rwlock_timing.c [new file with mode: 0644]
tests/benchmark/test_urcu.c [new file with mode: 0644]
tests/benchmark/test_urcu_assign.c [new file with mode: 0644]
tests/benchmark/test_urcu_bp.c [new file with mode: 0644]
tests/benchmark/test_urcu_defer.c [new file with mode: 0644]
tests/benchmark/test_urcu_gc.c [new file with mode: 0644]
tests/benchmark/test_urcu_hash.c [new file with mode: 0644]
tests/benchmark/test_urcu_hash.h [new file with mode: 0644]
tests/benchmark/test_urcu_hash_rw.c [new file with mode: 0644]
tests/benchmark/test_urcu_hash_unique.c [new file with mode: 0644]
tests/benchmark/test_urcu_lfq.c [new file with mode: 0644]
tests/benchmark/test_urcu_lfs.c [new file with mode: 0644]
tests/benchmark/test_urcu_lfs_rcu.c [new file with mode: 0644]
tests/benchmark/test_urcu_qsbr.c [new file with mode: 0644]
tests/benchmark/test_urcu_qsbr_gc.c [new file with mode: 0644]
tests/benchmark/test_urcu_qsbr_timing.c [new file with mode: 0644]
tests/benchmark/test_urcu_timing.c [new file with mode: 0644]
tests/benchmark/test_urcu_wfcq.c [new file with mode: 0644]
tests/benchmark/test_urcu_wfq.c [new file with mode: 0644]
tests/benchmark/test_urcu_wfs.c [new file with mode: 0644]
tests/common.sh [deleted file]
tests/common/api.h [new file with mode: 0644]
tests/common/cpuset.h [new file with mode: 0644]
tests/common/thread-id.h [new file with mode: 0644]
tests/cpuset.h [deleted file]
tests/rcutorture.h [deleted file]
tests/regression/Makefile.am [new file with mode: 0644]
tests/regression/rcutorture.h [new file with mode: 0644]
tests/regression/test_urcu_fork.c [new file with mode: 0644]
tests/regression/urcutorture.c [new file with mode: 0644]
tests/runall.sh [deleted file]
tests/runhash.sh [deleted file]
tests/runpaul-phase1.sh [deleted file]
tests/runpaul-phase2.sh [deleted file]
tests/runpaul-phase3.sh [deleted file]
tests/runpaul-phase4.sh [deleted file]
tests/runpaul-phase5.sh [deleted file]
tests/runpaul-phase6.sh [deleted file]
tests/runpaul-phase7.sh [deleted file]
tests/runtests-batch.sh [deleted file]
tests/runtests.sh [deleted file]
tests/subphase4.sh [deleted file]
tests/test_cycles_per_loop.c [deleted file]
tests/test_looplen.c [deleted file]
tests/test_mutex.c [deleted file]
tests/test_perthreadlock.c [deleted file]
tests/test_perthreadlock_timing.c [deleted file]
tests/test_rwlock.c [deleted file]
tests/test_rwlock_timing.c [deleted file]
tests/test_uatomic.c [deleted file]
tests/test_urcu.c [deleted file]
tests/test_urcu_assign.c [deleted file]
tests/test_urcu_bp.c [deleted file]
tests/test_urcu_defer.c [deleted file]
tests/test_urcu_fork.c [deleted file]
tests/test_urcu_gc.c [deleted file]
tests/test_urcu_hash.c [deleted file]
tests/test_urcu_hash.h [deleted file]
tests/test_urcu_hash_rw.c [deleted file]
tests/test_urcu_hash_unique.c [deleted file]
tests/test_urcu_lfq.c [deleted file]
tests/test_urcu_lfs.c [deleted file]
tests/test_urcu_lfs_rcu.c [deleted file]
tests/test_urcu_multiflavor-bp.c [deleted file]
tests/test_urcu_multiflavor-mb.c [deleted file]
tests/test_urcu_multiflavor-memb.c [deleted file]
tests/test_urcu_multiflavor-qsbr.c [deleted file]
tests/test_urcu_multiflavor-signal.c [deleted file]
tests/test_urcu_multiflavor.c [deleted file]
tests/test_urcu_multiflavor.h [deleted file]
tests/test_urcu_qsbr.c [deleted file]
tests/test_urcu_qsbr_gc.c [deleted file]
tests/test_urcu_qsbr_timing.c [deleted file]
tests/test_urcu_timing.c [deleted file]
tests/test_urcu_wfcq.c [deleted file]
tests/test_urcu_wfq.c [deleted file]
tests/test_urcu_wfs.c [deleted file]
tests/thread-id.h [deleted file]
tests/unit/Makefile.am [new file with mode: 0644]
tests/unit/test_uatomic.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor-bp.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor-mb.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor-memb.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor-qsbr.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor-signal.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor.c [new file with mode: 0644]
tests/unit/test_urcu_multiflavor.h [new file with mode: 0644]
tests/unit/urcu-asm.c [new file with mode: 0644]
tests/urcu-asm.c [deleted file]
tests/urcutorture.c [deleted file]

index 00dbc40dd8d4941ce6a3c6d694db2f0646c97fdd..7b6704bb418b000969309dac57abfd03e4d69652 100644 (file)
@@ -2,75 +2,77 @@ urcu/arch.h
 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
index 0a4d357a846b6f628fa279437609d4d8f6eccc1e..e09778febcda0d37710fd978bdaaa0abda51603e 100644 (file)
@@ -29,8 +29,7 @@ EXTRA_DIST = $(top_srcdir)/urcu/arch/*.h $(top_srcdir)/urcu/uatomic/*.h \
                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
@@ -84,3 +83,9 @@ pkgconfig_DATA = liburcu-cds.pc liburcu.pc liburcu-bp.pc liburcu-qsbr.pc \
 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
index 52b20d841b3124a1ddc95b2b078be47ee89d0af9..fc1240d9eaf2c4653bc8f86ab0e259425ba3fbb5 100644 (file)
@@ -293,6 +293,10 @@ AC_CONFIG_FILES([
        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
index aa36bf447d2a0bd84fd42b59cb91f43f1afb7d88..d8fc5ef59087542a9970dbade59412287045c690 100644 (file)
@@ -1,235 +1,8 @@
-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
diff --git a/tests/api.h b/tests/api.h
deleted file mode 100644 (file)
index dced0d8..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-#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
diff --git a/tests/benchmark/Makefile.am b/tests/benchmark/Makefile.am
new file mode 100644 (file)
index 0000000..e071034
--- /dev/null
@@ -0,0 +1,186 @@
+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
diff --git a/tests/benchmark/common.sh b/tests/benchmark/common.sh
new file mode 100644 (file)
index 0000000..9eb03f8
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# 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
+
diff --git a/tests/benchmark/runall.sh b/tests/benchmark/runall.sh
new file mode 100755 (executable)
index 0000000..ced1765
--- /dev/null
@@ -0,0 +1,104 @@
+#!/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
diff --git a/tests/benchmark/runhash.sh b/tests/benchmark/runhash.sh
new file mode 100755 (executable)
index 0000000..0ba20ef
--- /dev/null
@@ -0,0 +1,136 @@
+#!/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
diff --git a/tests/benchmark/runpaul-phase1.sh b/tests/benchmark/runpaul-phase1.sh
new file mode 100755 (executable)
index 0000000..d2c8649
--- /dev/null
@@ -0,0 +1,44 @@
+#!/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
diff --git a/tests/benchmark/runpaul-phase2.sh b/tests/benchmark/runpaul-phase2.sh
new file mode 100755 (executable)
index 0000000..bba9e3e
--- /dev/null
@@ -0,0 +1,47 @@
+#!/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
diff --git a/tests/benchmark/runpaul-phase3.sh b/tests/benchmark/runpaul-phase3.sh
new file mode 100755 (executable)
index 0000000..7c5f055
--- /dev/null
@@ -0,0 +1,50 @@
+#!/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
+
+
diff --git a/tests/benchmark/runpaul-phase4.sh b/tests/benchmark/runpaul-phase4.sh
new file mode 100755 (executable)
index 0000000..ede402c
--- /dev/null
@@ -0,0 +1,40 @@
+#!/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/
diff --git a/tests/benchmark/runpaul-phase5.sh b/tests/benchmark/runpaul-phase5.sh
new file mode 100644 (file)
index 0000000..bb4bfe7
--- /dev/null
@@ -0,0 +1,11 @@
+# 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
diff --git a/tests/benchmark/runpaul-phase6.sh b/tests/benchmark/runpaul-phase6.sh
new file mode 100644 (file)
index 0000000..5f65072
--- /dev/null
@@ -0,0 +1,7 @@
+sh runpaul-phase1.sh
+mkdir runpaul-phase1
+mv *.log runpaul-phase1/
+
+sh runpaul-phase2.sh
+mkdir runpaul-phase2
+mv *.log runpaul-phase2/
diff --git a/tests/benchmark/runpaul-phase7.sh b/tests/benchmark/runpaul-phase7.sh
new file mode 100755 (executable)
index 0000000..4c301da
--- /dev/null
@@ -0,0 +1,41 @@
+#!/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/
diff --git a/tests/benchmark/runtests-batch.sh b/tests/benchmark/runtests-batch.sh
new file mode 100755 (executable)
index 0000000..2da1401
--- /dev/null
@@ -0,0 +1,19 @@
+#!/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
+
diff --git a/tests/benchmark/runtests.sh b/tests/benchmark/runtests.sh
new file mode 100755 (executable)
index 0000000..6001174
--- /dev/null
@@ -0,0 +1,21 @@
+#!/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
+
diff --git a/tests/benchmark/subphase4.sh b/tests/benchmark/subphase4.sh
new file mode 100755 (executable)
index 0000000..d0d7587
--- /dev/null
@@ -0,0 +1,101 @@
+#!/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
diff --git a/tests/benchmark/test_cycles_per_loop.c b/tests/benchmark/test_cycles_per_loop.c
new file mode 100644 (file)
index 0000000..6ff100b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_looplen.c b/tests/benchmark/test_looplen.c
new file mode 100644 (file)
index 0000000..16674e7
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_mutex.c b/tests/benchmark/test_mutex.c
new file mode 100644 (file)
index 0000000..255acfc
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_perthreadlock.c b/tests/benchmark/test_perthreadlock.c
new file mode 100644 (file)
index 0000000..01c4fb0
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_perthreadlock_timing.c b/tests/benchmark/test_perthreadlock_timing.c
new file mode 100644 (file)
index 0000000..97bdd04
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_rwlock.c b/tests/benchmark/test_rwlock.c
new file mode 100644 (file)
index 0000000..32e3c39
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_rwlock_timing.c b/tests/benchmark/test_rwlock_timing.c
new file mode 100644 (file)
index 0000000..d916071
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu.c b/tests/benchmark/test_urcu.c
new file mode 100644 (file)
index 0000000..e87e235
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_assign.c b/tests/benchmark/test_urcu_assign.c
new file mode 100644 (file)
index 0000000..6c4adc3
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_bp.c b/tests/benchmark/test_urcu_bp.c
new file mode 100644 (file)
index 0000000..0f21da9
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_defer.c b/tests/benchmark/test_urcu_defer.c
new file mode 100644 (file)
index 0000000..80249bd
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_gc.c b/tests/benchmark/test_urcu_gc.c
new file mode 100644 (file)
index 0000000..1375a5e
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_hash.c b/tests/benchmark/test_urcu_hash.c
new file mode 100644 (file)
index 0000000..f862adb
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * 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);
+}
diff --git a/tests/benchmark/test_urcu_hash.h b/tests/benchmark/test_urcu_hash.h
new file mode 100644 (file)
index 0000000..c0727b7
--- /dev/null
@@ -0,0 +1,390 @@
+#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 */
diff --git a/tests/benchmark/test_urcu_hash_rw.c b/tests/benchmark/test_urcu_hash_rw.c
new file mode 100644 (file)
index 0000000..8802b9c
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_hash_unique.c b/tests/benchmark/test_urcu_hash_unique.c
new file mode 100644 (file)
index 0000000..adbbde0
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_lfq.c b/tests/benchmark/test_urcu_lfq.c
new file mode 100644 (file)
index 0000000..33d1e73
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_lfs.c b/tests/benchmark/test_urcu_lfs.c
new file mode 100644 (file)
index 0000000..33ba069
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_lfs_rcu.c b/tests/benchmark/test_urcu_lfs_rcu.c
new file mode 100644 (file)
index 0000000..dc07485
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_qsbr.c b/tests/benchmark/test_urcu_qsbr.c
new file mode 100644 (file)
index 0000000..e8ba5f6
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_qsbr_gc.c b/tests/benchmark/test_urcu_qsbr_gc.c
new file mode 100644 (file)
index 0000000..5fc15c0
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_qsbr_timing.c b/tests/benchmark/test_urcu_qsbr_timing.c
new file mode 100644 (file)
index 0000000..9b5195d
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_timing.c b/tests/benchmark/test_urcu_timing.c
new file mode 100644 (file)
index 0000000..e31b676
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_wfcq.c b/tests/benchmark/test_urcu_wfcq.c
new file mode 100644 (file)
index 0000000..d0814cd
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_wfq.c b/tests/benchmark/test_urcu_wfq.c
new file mode 100644 (file)
index 0000000..07ab72b
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * 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;
+}
diff --git a/tests/benchmark/test_urcu_wfs.c b/tests/benchmark/test_urcu_wfs.c
new file mode 100644 (file)
index 0000000..c74f8b7
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * 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;
+}
diff --git a/tests/common.sh b/tests/common.sh
deleted file mode 100644 (file)
index 9eb03f8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# 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
-
diff --git a/tests/common/api.h b/tests/common/api.h
new file mode 100644 (file)
index 0000000..1403359
--- /dev/null
@@ -0,0 +1,311 @@
+#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
diff --git a/tests/common/cpuset.h b/tests/common/cpuset.h
new file mode 100644 (file)
index 0000000..4d1f211
--- /dev/null
@@ -0,0 +1,45 @@
+#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 */
diff --git a/tests/common/thread-id.h b/tests/common/thread-id.h
new file mode 100644 (file)
index 0000000..9378edc
--- /dev/null
@@ -0,0 +1,55 @@
+#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 */
diff --git a/tests/cpuset.h b/tests/cpuset.h
deleted file mode 100644 (file)
index 3f1587d..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#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 */
diff --git a/tests/rcutorture.h b/tests/rcutorture.h
deleted file mode 100644 (file)
index f8548d8..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/regression/Makefile.am b/tests/regression/Makefile.am
new file mode 100644 (file)
index 0000000..2c0542f
--- /dev/null
@@ -0,0 +1,75 @@
+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 ..
diff --git a/tests/regression/rcutorture.h b/tests/regression/rcutorture.h
new file mode 100644 (file)
index 0000000..f8548d8
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * 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;
+}
diff --git a/tests/regression/test_urcu_fork.c b/tests/regression/test_urcu_fork.c
new file mode 100644 (file)
index 0000000..ce0c9ca
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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);
+}
diff --git a/tests/regression/urcutorture.c b/tests/regression/urcutorture.c
new file mode 100644 (file)
index 0000000..35096a6
--- /dev/null
@@ -0,0 +1,30 @@
+#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"
diff --git a/tests/runall.sh b/tests/runall.sh
deleted file mode 100755 (executable)
index 244766b..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/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
diff --git a/tests/runhash.sh b/tests/runhash.sh
deleted file mode 100755 (executable)
index 0ba20ef..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/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
diff --git a/tests/runpaul-phase1.sh b/tests/runpaul-phase1.sh
deleted file mode 100755 (executable)
index d2c8649..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/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
diff --git a/tests/runpaul-phase2.sh b/tests/runpaul-phase2.sh
deleted file mode 100755 (executable)
index bba9e3e..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/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
diff --git a/tests/runpaul-phase3.sh b/tests/runpaul-phase3.sh
deleted file mode 100755 (executable)
index 7c5f055..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/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
-
-
diff --git a/tests/runpaul-phase4.sh b/tests/runpaul-phase4.sh
deleted file mode 100755 (executable)
index ede402c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/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/
diff --git a/tests/runpaul-phase5.sh b/tests/runpaul-phase5.sh
deleted file mode 100644 (file)
index bb4bfe7..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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
diff --git a/tests/runpaul-phase6.sh b/tests/runpaul-phase6.sh
deleted file mode 100644 (file)
index 5f65072..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-sh runpaul-phase1.sh
-mkdir runpaul-phase1
-mv *.log runpaul-phase1/
-
-sh runpaul-phase2.sh
-mkdir runpaul-phase2
-mv *.log runpaul-phase2/
diff --git a/tests/runpaul-phase7.sh b/tests/runpaul-phase7.sh
deleted file mode 100755 (executable)
index 4c301da..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/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/
diff --git a/tests/runtests-batch.sh b/tests/runtests-batch.sh
deleted file mode 100755 (executable)
index 2da1401..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/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
-
diff --git a/tests/runtests.sh b/tests/runtests.sh
deleted file mode 100755 (executable)
index 6001174..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/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
-
diff --git a/tests/subphase4.sh b/tests/subphase4.sh
deleted file mode 100755 (executable)
index d0d7587..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/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
diff --git a/tests/test_cycles_per_loop.c b/tests/test_cycles_per_loop.c
deleted file mode 100644 (file)
index 6ff100b..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_looplen.c b/tests/test_looplen.c
deleted file mode 100644 (file)
index 16674e7..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_mutex.c b/tests/test_mutex.c
deleted file mode 100644 (file)
index 2f25454..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_perthreadlock.c b/tests/test_perthreadlock.c
deleted file mode 100644 (file)
index 39e2feb..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_perthreadlock_timing.c b/tests/test_perthreadlock_timing.c
deleted file mode 100644 (file)
index 97bdd04..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_rwlock.c b/tests/test_rwlock.c
deleted file mode 100644 (file)
index 5a0e8c1..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_rwlock_timing.c b/tests/test_rwlock_timing.c
deleted file mode 100644 (file)
index d916071..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_uatomic.c b/tests/test_uatomic.c
deleted file mode 100644 (file)
index 804ce7b..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu.c b/tests/test_urcu.c
deleted file mode 100644 (file)
index 2764878..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_assign.c b/tests/test_urcu_assign.c
deleted file mode 100644 (file)
index dc6bf2f..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_bp.c b/tests/test_urcu_bp.c
deleted file mode 100644 (file)
index 9ec5f3e..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_defer.c b/tests/test_urcu_defer.c
deleted file mode 100644 (file)
index 4e785c4..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_fork.c b/tests/test_urcu_fork.c
deleted file mode 100644 (file)
index 6e454b5..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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);
-}
diff --git a/tests/test_urcu_gc.c b/tests/test_urcu_gc.c
deleted file mode 100644 (file)
index 5c57f3f..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_hash.c b/tests/test_urcu_hash.c
deleted file mode 100644 (file)
index f862adb..0000000
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * 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);
-}
diff --git a/tests/test_urcu_hash.h b/tests/test_urcu_hash.h
deleted file mode 100644 (file)
index cd064e6..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-#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 */
diff --git a/tests/test_urcu_hash_rw.c b/tests/test_urcu_hash_rw.c
deleted file mode 100644 (file)
index 8802b9c..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_hash_unique.c b/tests/test_urcu_hash_unique.c
deleted file mode 100644 (file)
index adbbde0..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_lfq.c b/tests/test_urcu_lfq.c
deleted file mode 100644 (file)
index 5717f23..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_lfs.c b/tests/test_urcu_lfs.c
deleted file mode 100644 (file)
index 5659d9a..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_lfs_rcu.c b/tests/test_urcu_lfs_rcu.c
deleted file mode 100644 (file)
index b76bde1..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor-bp.c b/tests/test_urcu_multiflavor-bp.c
deleted file mode 100644 (file)
index 199818b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor-mb.c b/tests/test_urcu_multiflavor-mb.c
deleted file mode 100644 (file)
index e4ba6a4..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor-memb.c b/tests/test_urcu_multiflavor-memb.c
deleted file mode 100644 (file)
index 583f2e1..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor-qsbr.c b/tests/test_urcu_multiflavor-qsbr.c
deleted file mode 100644 (file)
index 64f32f4..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor-signal.c b/tests/test_urcu_multiflavor-signal.c
deleted file mode 100644 (file)
index 816c615..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_multiflavor.c b/tests/test_urcu_multiflavor.c
deleted file mode 100644 (file)
index cd573ca..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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);
-}
diff --git a/tests/test_urcu_multiflavor.h b/tests/test_urcu_multiflavor.h
deleted file mode 100644 (file)
index 419ad5d..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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);
-
diff --git a/tests/test_urcu_qsbr.c b/tests/test_urcu_qsbr.c
deleted file mode 100644 (file)
index 85d8430..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_qsbr_gc.c b/tests/test_urcu_qsbr_gc.c
deleted file mode 100644 (file)
index e0a2004..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_qsbr_timing.c b/tests/test_urcu_qsbr_timing.c
deleted file mode 100644 (file)
index 9b5195d..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_timing.c b/tests/test_urcu_timing.c
deleted file mode 100644 (file)
index e31b676..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_wfcq.c b/tests/test_urcu_wfcq.c
deleted file mode 100644 (file)
index f04c9bd..0000000
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_wfq.c b/tests/test_urcu_wfq.c
deleted file mode 100644 (file)
index 382a1f6..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/test_urcu_wfs.c b/tests/test_urcu_wfs.c
deleted file mode 100644 (file)
index 0fe7d4c..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * 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;
-}
diff --git a/tests/thread-id.h b/tests/thread-id.h
deleted file mode 100644 (file)
index 9378edc..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#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 */
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
new file mode 100644 (file)
index 0000000..1fa8b71
--- /dev/null
@@ -0,0 +1,61 @@
+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
diff --git a/tests/unit/test_uatomic.c b/tests/unit/test_uatomic.c
new file mode 100644 (file)
index 0000000..804ce7b
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor-bp.c b/tests/unit/test_urcu_multiflavor-bp.c
new file mode 100644 (file)
index 0000000..199818b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor-mb.c b/tests/unit/test_urcu_multiflavor-mb.c
new file mode 100644 (file)
index 0000000..e4ba6a4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor-memb.c b/tests/unit/test_urcu_multiflavor-memb.c
new file mode 100644 (file)
index 0000000..583f2e1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor-qsbr.c b/tests/unit/test_urcu_multiflavor-qsbr.c
new file mode 100644 (file)
index 0000000..64f32f4
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor-signal.c b/tests/unit/test_urcu_multiflavor-signal.c
new file mode 100644 (file)
index 0000000..816c615
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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;
+}
diff --git a/tests/unit/test_urcu_multiflavor.c b/tests/unit/test_urcu_multiflavor.c
new file mode 100644 (file)
index 0000000..cd573ca
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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);
+}
diff --git a/tests/unit/test_urcu_multiflavor.h b/tests/unit/test_urcu_multiflavor.h
new file mode 100644 (file)
index 0000000..419ad5d
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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);
+
diff --git a/tests/unit/urcu-asm.c b/tests/unit/urcu-asm.c
new file mode 100644 (file)
index 0000000..b616d34
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 */");
+}
diff --git a/tests/urcu-asm.c b/tests/urcu-asm.c
deleted file mode 100644 (file)
index b616d34..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 */");
-}
diff --git a/tests/urcutorture.c b/tests/urcutorture.c
deleted file mode 100644 (file)
index 35096a6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#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"
This page took 0.308225 seconds and 4 git commands to generate.