From 0562a3d00f16e24ad7e30e3137663b153322a4ca Mon Sep 17 00:00:00 2001 From: khizmax Date: Sun, 6 Mar 2016 11:43:36 +0300 Subject: [PATCH] Migrated queue stress test to gtest framework --- build/Makefile | 20 +- projects/Win/vc14/cds.sln | 41 +- projects/Win/vc14/stress-framework.vcxproj | 2 + .../Win/vc14/stress-framework.vcxproj.filters | 6 + projects/Win/vc14/stress-queue.vcxproj | 256 ++++++++ .../Win/vc14/stress-queue.vcxproj.filters | 54 ++ projects/Win/vc14/unit-queue.vcxproj | 318 ---------- projects/source.unit.queue.mk | 8 - test/stress/CMakeLists.txt | 6 + test/stress/data/test-debug.conf | 65 +- test/stress/data/test-express.conf | 63 +- test/stress/data/test.conf | 63 +- test/stress/framework/michael_alloc.cpp | 35 ++ test/stress/framework/michael_alloc.h | 95 +++ test/stress/lock/win32_lock.h | 71 +++ test/stress/michael_alloc.h | 95 +++ test/stress/queue/CMakeLists.txt | 26 + test/stress/queue/bounded_queue_fulness.cpp | 162 +++++ test/stress/queue/intrusive_push_pop.cpp | 583 ++++++++++++++++++ .../stress}/queue/intrusive_queue_type.h | 146 +---- test/stress/queue/pop.cpp | 249 ++++++++ test/stress/queue/print_stat.h | 125 ++++ test/stress/queue/push.cpp | 252 ++++++++ test/stress/queue/push_pop.cpp | 404 ++++++++++++ .../unit => test/stress}/queue/queue_type.h | 290 +++++---- test/stress/queue/random.cpp | 330 ++++++++++ {tests/unit => test/stress}/queue/std_queue.h | 7 +- tests/CMakeLists.txt | 4 +- tests/unit/CMakeLists.txt | 1 - tests/unit/queue/CMakeLists.txt | 13 - tests/unit/queue/bounded_queue_fulness.cpp | 167 ----- tests/unit/queue/intrusive_queue_defs.h | 194 ------ .../queue/intrusive_queue_reader_writer.cpp | 492 --------------- tests/unit/queue/queue_defs.h | 275 --------- tests/unit/queue/queue_pop.cpp | 255 -------- tests/unit/queue/queue_push.cpp | 266 -------- tests/unit/queue/queue_random.cpp | 327 ---------- tests/unit/queue/queue_reader_writer.cpp | 394 ------------ 38 files changed, 3124 insertions(+), 3036 deletions(-) create mode 100644 projects/Win/vc14/stress-queue.vcxproj create mode 100644 projects/Win/vc14/stress-queue.vcxproj.filters delete mode 100644 projects/Win/vc14/unit-queue.vcxproj delete mode 100644 projects/source.unit.queue.mk create mode 100644 test/stress/framework/michael_alloc.cpp create mode 100644 test/stress/framework/michael_alloc.h create mode 100644 test/stress/lock/win32_lock.h create mode 100644 test/stress/michael_alloc.h create mode 100644 test/stress/queue/CMakeLists.txt create mode 100644 test/stress/queue/bounded_queue_fulness.cpp create mode 100644 test/stress/queue/intrusive_push_pop.cpp rename {tests/unit => test/stress}/queue/intrusive_queue_type.h (80%) create mode 100644 test/stress/queue/pop.cpp create mode 100644 test/stress/queue/print_stat.h create mode 100644 test/stress/queue/push.cpp create mode 100644 test/stress/queue/push_pop.cpp rename {tests/unit => test/stress}/queue/queue_type.h (72%) create mode 100644 test/stress/queue/random.cpp rename {tests/unit => test/stress}/queue/std_queue.h (95%) delete mode 100644 tests/unit/queue/CMakeLists.txt delete mode 100644 tests/unit/queue/bounded_queue_fulness.cpp delete mode 100644 tests/unit/queue/intrusive_queue_defs.h delete mode 100644 tests/unit/queue/intrusive_queue_reader_writer.cpp delete mode 100644 tests/unit/queue/queue_defs.h delete mode 100644 tests/unit/queue/queue_pop.cpp delete mode 100644 tests/unit/queue/queue_push.cpp delete mode 100644 tests/unit/queue/queue_random.cpp delete mode 100644 tests/unit/queue/queue_reader_writer.cpp diff --git a/build/Makefile b/build/Makefile index 2a0e1af4..b20d9eeb 100644 --- a/build/Makefile +++ b/build/Makefile @@ -144,10 +144,6 @@ include ../projects/source.unit.set.mk CDSUNIT_SET_SOURCES := $(CDSUNIT_SET_SOURCES:%.cpp=../%.cpp) CDSUNIT_SET_OBJS := $(CDSUNIT_SET_SOURCES:%.cpp=%.o) -include ../projects/source.unit.queue.mk -CDSUNIT_QUEUE_SOURCES := $(CDSUNIT_QUEUE_SOURCES:%.cpp=../%.cpp) -CDSUNIT_QUEUE_OBJS := $(CDSUNIT_QUEUE_SOURCES:%.cpp=%.o) - include ../projects/source.unit.pqueue.mk CDSUNIT_PQUEUE_SOURCES := $(CDSUNIT_PQUEUE_SOURCES:%.cpp=../%.cpp) CDSUNIT_PQUEUE_OBJS := $(CDSUNIT_PQUEUE_SOURCES:%.cpp=%.o) @@ -156,7 +152,7 @@ include ../projects/source.unit.misc.mk CDSUNIT_MISC_SOURCES := $(CDSUNIT_MISC_SOURCES:%.cpp=../%.cpp) CDSUNIT_MISC_OBJS := $(CDSUNIT_MISC_SOURCES:%.cpp=%.o) -TEST_OBJ_FILE := $(CDSUNIT_COMMON_FILE) $(CDSUNIT_MAP_OBJS) $(CDSUNIT_SET_OBJS) $(CDSUNIT_QUEUE_OBJS) $(CDSUNIT_PQUEUE_OBJS) \ +TEST_OBJ_FILE := $(CDSUNIT_COMMON_FILE) $(CDSUNIT_MAP_OBJS) $(CDSUNIT_SET_OBJS) $(CDSUNIT_PQUEUE_OBJS) \ $(CDSUNIT_STACK_OBJS) $(CDSUNIT_MISC_OBJS) TEST_OBJ_FILE_DEPS := $(TEST_OBJ_FILE:%.o=%.d) @@ -166,14 +162,12 @@ $(TEST_OBJ_FILE): %.o: %.cpp CDSUNIT_MAP_EXE=$(BIN_PATH)/cdsu-map CDSUNIT_SET_EXE=$(BIN_PATH)/cdsu-set -CDSUNIT_QUEUE_EXE=$(BIN_PATH)/cdsu-queue CDSUNIT_PQUEUE_EXE=$(BIN_PATH)/cdsu-pqueue CDSUNIT_MISC_EXE=$(BIN_PATH)/cdsu-misc -CDSUNIT_EXE_FILES= $(CDSUNIT_MAP_EXE) $(CDSUNIT_SET_EXE) $(CDSUNIT_QUEUE_EXE) $(CDSUNIT_PQUEUE_EXE) $(CDSUNIT_MISC_EXE) +CDSUNIT_EXE_FILES= $(CDSUNIT_MAP_EXE) $(CDSUNIT_SET_EXE) $(CDSUNIT_PQUEUE_EXE) $(CDSUNIT_MISC_EXE) unit-map: $(CDSUNIT_MAP_EXE) unit-set: $(CDSUNIT_SET_EXE) -unit-queue: $(CDSUNIT_QUEUE_EXE) unit-pqueue: $(CDSUNIT_PQUEUE_EXE) ifeq ($(platform),mingw) @@ -197,9 +191,6 @@ $(CDSUNIT_MAP_EXE) : $(CDSUNIT_MAP_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OB $(CDSUNIT_SET_EXE) : $(CDSUNIT_SET_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_SET_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_LIBS) $(LDLIBS) -$(CDSUNIT_QUEUE_EXE) : $(CDSUNIT_QUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) - $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_QUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_LIBS) $(LDLIBS) - $(CDSUNIT_PQUEUE_EXE) : $(CDSUNIT_PQUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_PQUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_LIBS) $(LDLIBS) @@ -209,15 +200,13 @@ $(CDSUNIT_MISC_EXE) : $(CDSUNIT_MISC_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_ CDSUNIT_MAP_EXE_DBG=$(CDSUNIT_MAP_EXE)-d CDSUNIT_SET_EXE_DBG=$(CDSUNIT_SET_EXE)-d -CDSUNIT_QUEUE_EXE_DBG=$(CDSUNIT_QUEUE_EXE)-d CDSUNIT_PQUEUE_EXE_DBG=$(CDSUNIT_PQUEUE_EXE)-d CDSUNIT_MISC_EXE_DBG=$(CDSUNIT_MISC_EXE)-d -CDSUNIT_EXE_DBG_FILES= $(CDSUNIT_MAP_EXE_DBG) $(CDSUNIT_SET_EXE_DBG) $(CDSUNIT_QUEUE_EXE_DBG) $(CDSUNIT_PQUEUE_EXE_DBG) \ +CDSUNIT_EXE_DBG_FILES= $(CDSUNIT_MAP_EXE_DBG) $(CDSUNIT_SET_EXE_DBG) $(CDSUNIT_PQUEUE_EXE_DBG) \ $(CDSUNIT_MISC_EXE_DBG) unit-map-dbg: $(CDSUNIT_MAP_EXE_DBG) unit-set-dbg: $(CDSUNIT_SET_EXE_DBG) -unit-queue-dbg: $(CDSUNIT_QUEUE_EXE_DBG) unit-pqueue-dbg: $(CDSUNIT_PQUEUE_EXE_DBG) ifeq ($(platform),mingw) @@ -241,9 +230,6 @@ $(CDSUNIT_MAP_EXE_DBG) : $(CDSUNIT_MAP_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMO $(CDSUNIT_SET_EXE_DBG) : $(CDSUNIT_SET_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_SET_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_DEBUG_LIBS) $(LDLIBS) -$(CDSUNIT_QUEUE_EXE_DBG) : $(CDSUNIT_QUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) - $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_QUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_DEBUG_LIBS) $(LDLIBS) - $(CDSUNIT_PQUEUE_EXE_DBG) : $(CDSUNIT_PQUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) $(CXX) $(LD_OPTS) -L$(BIN_PATH) $(CDSUNIT_PQUEUE_OBJS) $(CDSUNIT_COMMON_FILE) $(TEST_COMMON_OBJS) -o $@ $(LD_BOOST_THREAD_LIB) $(LD_TEST_COMMON_DEBUG_LIBS) $(LDLIBS) diff --git a/projects/Win/vc14/cds.sln b/projects/Win/vc14/cds.sln index 8c1b24bf..0cf53c78 100644 --- a/projects/Win/vc14/cds.sln +++ b/projects/Win/vc14/cds.sln @@ -29,12 +29,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit-misc", "unit-misc.vcxp {408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit-queue", "unit-queue.vcxproj", "{6C15AF8A-4A99-49F9-BCF0-1BF36771099A}" - ProjectSection(ProjectDependencies) = postProject - {61179F2F-07E1-490D-B64D-D85A90B6EF81} = {61179F2F-07E1-490D-B64D-D85A90B6EF81} - {408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239} - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "single-threaded test", "single-threaded test", "{B8C24D26-A3BF-4DA6-B64C-142CBA4BFE75}" ProjectSection(SolutionItems) = preProject ..\..\..\tests\test-hdr\size_check.h = ..\..\..\tests\test-hdr\size_check.h @@ -195,6 +189,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-list", "gtest-list.vc EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "stress", "stress", "{10E1FAF2-904D-405E-8AB5-6878A1B03346}" + ProjectSection(SolutionItems) = preProject + ..\..\..\test\stress\michael_alloc.h = ..\..\..\test\stress\michael_alloc.h + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-framework", "stress-framework.vcxproj", "{A34CED07-A442-4FA1-81C4-F8B9CD3C832B}" EndProject @@ -204,6 +201,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-stack", "stress-stac {408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stress-queue", "stress-queue.vcxproj", "{50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}" + ProjectSection(ProjectDependencies) = postProject + {A34CED07-A442-4FA1-81C4-F8B9CD3C832B} = {A34CED07-A442-4FA1-81C4-F8B9CD3C832B} + {408FE9BC-44F0-4E6A-89FA-D6F952584239} = {408FE9BC-44F0-4E6A-89FA-D6F952584239} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -250,18 +253,6 @@ Global {77350FDC-9E51-438B-9A8F-D2FEA11D46B2}.Release|Win32.Build.0 = Release|Win32 {77350FDC-9E51-438B-9A8F-D2FEA11D46B2}.Release|x64.ActiveCfg = Release|x64 {77350FDC-9E51-438B-9A8F-D2FEA11D46B2}.Release|x64.Build.0 = Release|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Debug|Win32.ActiveCfg = Debug|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Debug|Win32.Build.0 = Debug|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Debug|x64.ActiveCfg = Debug|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Debug|x64.Build.0 = Debug|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.DebugVLD|Win32.ActiveCfg = Debug|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.DebugVLD|Win32.Build.0 = Debug|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.DebugVLD|x64.ActiveCfg = DebugVLD|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.DebugVLD|x64.Build.0 = DebugVLD|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Release|Win32.ActiveCfg = Release|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Release|Win32.Build.0 = Release|Win32 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Release|x64.ActiveCfg = Release|x64 - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A}.Release|x64.Build.0 = Release|x64 {282E9A9A-386A-40FB-A483-994BACE24830}.Debug|Win32.ActiveCfg = Debug|Win32 {282E9A9A-386A-40FB-A483-994BACE24830}.Debug|Win32.Build.0 = Debug|Win32 {282E9A9A-386A-40FB-A483-994BACE24830}.Debug|x64.ActiveCfg = Debug|x64 @@ -514,6 +505,18 @@ Global {5E1C3684-9463-4A98-BAFC-9BD51F179BB6}.Release|Win32.Build.0 = Release|Win32 {5E1C3684-9463-4A98-BAFC-9BD51F179BB6}.Release|x64.ActiveCfg = Release|x64 {5E1C3684-9463-4A98-BAFC-9BD51F179BB6}.Release|x64.Build.0 = Release|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Debug|Win32.ActiveCfg = Debug|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Debug|Win32.Build.0 = Debug|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Debug|x64.ActiveCfg = Debug|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Debug|x64.Build.0 = Debug|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.DebugVLD|Win32.ActiveCfg = DebugVLD|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.DebugVLD|Win32.Build.0 = DebugVLD|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.DebugVLD|x64.ActiveCfg = DebugVLD|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.DebugVLD|x64.Build.0 = DebugVLD|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Release|Win32.ActiveCfg = Release|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Release|Win32.Build.0 = Release|Win32 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Release|x64.ActiveCfg = Release|x64 + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -521,7 +524,6 @@ Global GlobalSection(NestedProjects) = preSolution {61179F2F-07E1-490D-B64D-D85A90B6EF81} = {B30CA283-1796-4763-92C3-2E4848D443F7} {77350FDC-9E51-438B-9A8F-D2FEA11D46B2} = {B30CA283-1796-4763-92C3-2E4848D443F7} - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A} = {B30CA283-1796-4763-92C3-2E4848D443F7} {282E9A9A-386A-40FB-A483-994BACE24830} = {B8C24D26-A3BF-4DA6-B64C-142CBA4BFE75} {C5E76975-B87B-4B9E-8596-B01DDA683FCA} = {B8C24D26-A3BF-4DA6-B64C-142CBA4BFE75} {6BB7A27F-FC59-4267-B6FA-D034176D1459} = {B30CA283-1796-4763-92C3-2E4848D443F7} @@ -545,6 +547,7 @@ Global {83FC591C-2CA2-4631-AD13-218FF4C27692} = {810490B7-31E5-49AE-8455-CAF99A9658B6} {A34CED07-A442-4FA1-81C4-F8B9CD3C832B} = {10E1FAF2-904D-405E-8AB5-6878A1B03346} {5E1C3684-9463-4A98-BAFC-9BD51F179BB6} = {10E1FAF2-904D-405E-8AB5-6878A1B03346} + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C} = {10E1FAF2-904D-405E-8AB5-6878A1B03346} EndGlobalSection GlobalSection(DPCodeReviewSolutionGUID) = preSolution DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} diff --git a/projects/Win/vc14/stress-framework.vcxproj b/projects/Win/vc14/stress-framework.vcxproj index 335e9da4..c80be1ed 100644 --- a/projects/Win/vc14/stress-framework.vcxproj +++ b/projects/Win/vc14/stress-framework.vcxproj @@ -28,6 +28,7 @@ + @@ -39,6 +40,7 @@ 4267 + diff --git a/projects/Win/vc14/stress-framework.vcxproj.filters b/projects/Win/vc14/stress-framework.vcxproj.filters index 7b109740..557cbb20 100644 --- a/projects/Win/vc14/stress-framework.vcxproj.filters +++ b/projects/Win/vc14/stress-framework.vcxproj.filters @@ -18,6 +18,9 @@ Header Files + + Header Files + @@ -29,6 +32,9 @@ Source Files + + Source Files + diff --git a/projects/Win/vc14/stress-queue.vcxproj b/projects/Win/vc14/stress-queue.vcxproj new file mode 100644 index 00000000..b0c6b96f --- /dev/null +++ b/projects/Win/vc14/stress-queue.vcxproj @@ -0,0 +1,256 @@ + + + + + DebugVLD + Win32 + + + DebugVLD + x64 + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + /bigobj %(AdditionalOptions) + /bigobj %(AdditionalOptions) + /bigobj %(AdditionalOptions) + /bigobj %(AdditionalOptions) + /bigobj %(AdditionalOptions) + /bigobj %(AdditionalOptions) + + + + + + + + + + + {50B2EC4B-A118-4E7B-ABC7-2EA8B685A58C} + Win32Proj + stress_queue + 8.1 + stress-queue + + + + Application + true + v140 + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + true + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + $(ProjectName)_d + + + false + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + + + false + $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ + $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies) + + + + + NotUsing + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtestd.lib;stress-framework_d.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(GTEST_LIB32);$(GTEST_ROOT)/lib/x86;$(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtest.lib;stres-framework.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)..\..\..;$(GTEST_ROOT)/include;$(SolutionDir)..\..\..\test\include;$(SolutionDir)..\..\..\test\stress;$(BOOST_PATH);%(AdditionalIncludeDirectories) + + + Console + true + true + true + $(GTEST_LIB64);$(GTEST_ROOT)/lib/x64;$(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;%(AdditionalLibraryDirectories);$(OutDir) + gtest.lib;stres-framework.lib;%(AdditionalDependencies) + + + + + + \ No newline at end of file diff --git a/projects/Win/vc14/stress-queue.vcxproj.filters b/projects/Win/vc14/stress-queue.vcxproj.filters new file mode 100644 index 00000000..f65383d0 --- /dev/null +++ b/projects/Win/vc14/stress-queue.vcxproj.filters @@ -0,0 +1,54 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/projects/Win/vc14/unit-queue.vcxproj b/projects/Win/vc14/unit-queue.vcxproj deleted file mode 100644 index d5d6a1b3..00000000 --- a/projects/Win/vc14/unit-queue.vcxproj +++ /dev/null @@ -1,318 +0,0 @@ - - - - - DebugVLD - Win32 - - - DebugVLD - x64 - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {6C15AF8A-4A99-49F9-BCF0-1BF36771099A} - unitqueue - Win32Proj - 8.1 - - - - Application - Unicode - true - v140 - - - Application - Unicode - v140 - - - Application - Unicode - v140 - - - Application - Unicode - true - v140 - - - Application - Unicode - v140 - - - Application - Unicode - v140 - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - false - false - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - false - false - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - false - $(SolutionDir)..\..\..\bin\vc.$(PlatformToolset)\$(Platform)-release\ - $(SolutionDir)..\..\..\obj\vc.$(PlatformToolset)\$(Platform)\$(ProjectName)\$(Configuration)\ - false - AllRules.ruleset - AllRules.ruleset - - - - - AllRules.ruleset - AllRules.ruleset - - - - - AllRules.ruleset - - - AllRules.ruleset - - - $(ProjectName)_d - $(ProjectName)_d - $(ProjectName)_d - $(ProjectName)_d - - - - /bigobj /Zc:inline %(AdditionalOptions) - Disabled - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - 4520 - - - unit-prerequisites_d.lib;%(AdditionalDependencies) - $(TargetPath) - $(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - MachineX86 - MultiplyDefinedSymbolOnly - - - - - /bigobj /Zc:inline %(AdditionalOptions) - Disabled - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - CDS_USE_VLD;WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - EditAndContinue - 4520 - - - unit-prerequisites_d.lib;%(AdditionalDependencies) - $(TargetPath) - $(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - MachineX86 - MultiplyDefinedSymbolOnly - - - - - X64 - - - /bigobj /Zc:inline %(AdditionalOptions) - Disabled - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - 4520 - - - unit-prerequisites_d.lib;%(AdditionalDependencies) - $(TargetPath) - $(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - MachineX64 - MultiplyDefinedSymbolOnly - - - - - X64 - - - /bigobj /Zc:inline %(AdditionalOptions) - Disabled - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - CDS_USE_VLD;WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - true - EnableFastChecks - MultiThreadedDebugDLL - - - Level3 - ProgramDatabase - 4520 - - - unit-prerequisites_d.lib;%(AdditionalDependencies) - $(TargetPath) - $(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - MachineX64 - MultiplyDefinedSymbolOnly - - - - - /bigobj /Zc:inline %(AdditionalOptions) - MaxSpeed - AnySuitable - true - Speed - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - 4520 - - - unit-prerequisites.lib;%(AdditionalDependencies) - $(BOOST_PATH)/stage32/lib;$(BOOST_PATH)/stage/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX86 - $(TargetPath) - MultiplyDefinedSymbolOnly - - - - - X64 - - - /bigobj /Zc:inline %(AdditionalOptions) - MaxSpeed - AnySuitable - true - Speed - $(SolutionDir)..\..\..;$(SolutionDir)..\..\..\tests\unit;$(SolutionDir)..\..\..\tests;$(BOOST_PATH);%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;_SCL_SECURE=0;%(PreprocessorDefinitions) - MultiThreadedDLL - true - - - Level3 - ProgramDatabase - 4520 - - - unit-prerequisites.lib;%(AdditionalDependencies) - $(BOOST_PATH)/stage64/lib;$(BOOST_PATH)/bin;$(OutDir);%(AdditionalLibraryDirectories) - true - Console - true - true - MachineX64 - $(TargetPath) - MultiplyDefinedSymbolOnly - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/projects/source.unit.queue.mk b/projects/source.unit.queue.mk deleted file mode 100644 index 0c80d48d..00000000 --- a/projects/source.unit.queue.mk +++ /dev/null @@ -1,8 +0,0 @@ - -CDSUNIT_QUEUE_SOURCES := \ - tests/unit/queue/bounded_queue_fulness.cpp \ - tests/unit/queue/queue_pop.cpp \ - tests/unit/queue/queue_push.cpp \ - tests/unit/queue/queue_random.cpp \ - tests/unit/queue/queue_reader_writer.cpp \ - tests/unit/queue/intrusive_queue_reader_writer.cpp diff --git a/test/stress/CMakeLists.txt b/test/stress/CMakeLists.txt index 85a6d7de..0ac5aa5b 100644 --- a/test/stress/CMakeLists.txt +++ b/test/stress/CMakeLists.txt @@ -3,11 +3,17 @@ set(CDSSTRESS_FRAMEWORK_LIBRARY stress-framework) set(CDSSTRESS_FRAMEWORK_SOURCES framework/city.cpp framework/config.cpp + framework/michael_alloc.cpp framework/stress_test.cpp ) add_library(${CDSSTRESS_FRAMEWORK_LIBRARY} OBJECT ${CDSSTRESS_FRAMEWORK_SOURCES}) +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/queue) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/stack) file(GLOB CONF_FILES ${PROJECT_SOURCE_DIR}/test/stress/data/*.conf) diff --git a/test/stress/data/test-debug.conf b/test/stress/data/test-debug.conf index 3052e041..19f200b9 100644 --- a/test/stress/data/test-debug.conf +++ b/test/stress/data/test-debug.conf @@ -82,29 +82,62 @@ FCIterate=0 FCCombinePassCount=4 FCCompactFactor=64 -[Queue_Push] -ThreadCount=8 +[queue_push] +ThreadCount=4 QueueSize=100000 - -[Queue_Pop] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_pop] ThreadCount=8 QueueSize=100000 - -[Queue_ReaderWriter] -ReaderCount=3 -WriterCount=3 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_push_pop] +ProducerCount=3 +ConsumerCount=3 QueueSize=100000 - -[IntrusiveQueue_ReaderWriter] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_random] +ThreadCount=4 +QueueSize=500000 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[intrusive_queue_push_pop] ReaderCount=3 WriterCount=3 QueueSize=100000 - -[Queue_Random] -ThreadCount=4 -QueueSize=500000 - -[BoundedQueue_Fullness] +# Flat combining queue parameters +FCCompactFactor=64 +FCPassCount=8 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[bounded_queue_fulness] ThreadCount=4 QueueSize=1024 PassCount=100000 diff --git a/test/stress/data/test-express.conf b/test/stress/data/test-express.conf index fa9b8ee9..488f71c5 100644 --- a/test/stress/data/test-express.conf +++ b/test/stress/data/test-express.conf @@ -83,29 +83,62 @@ FCIterate=0 FCCombinePassCount=4 FCCompactFactor=64 -[Queue_Push] +[queue_push] ThreadCount=8 QueueSize=500000 - -[Queue_Pop] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_pop] ThreadCount=8 QueueSize=500000 - -[Queue_ReaderWriter] -ReaderCount=4 -WriterCount=4 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_push_pop] +ConsumerCount=4 +ProducerCount=4 QueueSize=500000 - -[IntrusiveQueue_ReaderWriter] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[queue_random] +ThreadCount=8 +QueueSize=500000 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[intrusive_queue_push_pop] ReaderCount=4 WriterCount=4 QueueSize=500000 - -[Queue_Random] -ThreadCount=8 -QueueSize=500000 - -[BoundedQueue_Fullness] +# Flat combining queue parameters +FCCompactFactor=64 +FCPassCount=8 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=64 + +[bounded_queue_fulness] ThreadCount=4 QueueSize=1024 PassCount=100000 diff --git a/test/stress/data/test.conf b/test/stress/data/test.conf index a74aaa1e..3d7f175a 100644 --- a/test/stress/data/test.conf +++ b/test/stress/data/test.conf @@ -82,29 +82,62 @@ FCIterate=0 FCCombinePassCount=8 FCCompactFactor=64 -[Queue_Push] +[queue_push] ThreadCount=8 QueueSize=5000000 - -[Queue_Pop] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=256 + +[queue_pop] ThreadCount=8 QueueSize=5000000 - -[Queue_ReaderWriter] -ReaderCount=4 -WriterCount=4 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=256 + +[queue_push_pop] +ConsumerCount=4 +ProducerCount=4 QueueSize=5000000 - -[IntrusiveQueue_ReaderWriter] +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=256 + +[queue_random] +ThreadCount=8 +QueueSize=5000000 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=256 + +[intrusive_queue_push_pop] ReaderCount=4 WriterCount=4 QueueSize=5000000 - -[Queue_Random] -ThreadCount=8 -QueueSize=5000000 - -[BoundedQueue_Fullness] +# Flat combining queue parameters +FCCompactFactor=64 +FCPassCount=8 +# SegmentedQueue parameters: +# SegmentedQueue_Iterate: +# 1 - run test iteratively for segment size from 4 up to SegmentedQueue_SegmentSize +# 0 - run test for segment size equal to SegmentedQueue_SegmentSize +SegmentedQueue_Iterate=0 +SegmentedQueue_SegmentSize=256 + +[bounded_queue_fulness] ThreadCount=8 QueueSize=1024 PassCount=1000000 diff --git a/test/stress/framework/michael_alloc.cpp b/test/stress/framework/michael_alloc.cpp new file mode 100644 index 00000000..ec6e3aa8 --- /dev/null +++ b/test/stress/framework/michael_alloc.cpp @@ -0,0 +1,35 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "michael_alloc.h" + +namespace memory { + michael_heap s_MichaelHeap; +} diff --git a/test/stress/framework/michael_alloc.h b/test/stress/framework/michael_alloc.h new file mode 100644 index 00000000..68305990 --- /dev/null +++ b/test/stress/framework/michael_alloc.h @@ -0,0 +1,95 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSSTRESS_MICHAEL_ALLOC_H +#define CDSSTRESS_MICHAEL_ALLOC_H + +#include +#include + +namespace memory { + + typedef cds::memory::michael::Heap< + cds::memory::michael::opt::check_bounds< cds::memory::michael::debug_bound_checking > + > michael_heap; + extern michael_heap s_MichaelHeap; + + template + class MichaelAllocator + { + typedef std::allocator std_allocator; + public: + // Declare typedefs from std::allocator + typedef typename std_allocator::const_pointer const_pointer; + typedef typename std_allocator::pointer pointer; + typedef typename std_allocator::const_reference const_reference; + typedef typename std_allocator::reference reference; + typedef typename std_allocator::difference_type difference_type; + typedef typename std_allocator::size_type size_type; + typedef typename std_allocator::value_type value_type; + + // Allocation function + pointer allocate( size_type _Count, const void* /*_Hint*/ = nullptr ) + { + return reinterpret_cast( s_MichaelHeap.alloc( sizeof(T) * _Count )); + } + + // Deallocation function + void deallocate( pointer _Ptr, size_type /*_Count*/ ) + { + s_MichaelHeap.free( _Ptr ); + } + + pointer address( reference r ) const + { + return &r; + } + const_pointer address( const_reference r ) const + { + return &r; + } + void construct( pointer p, const T& val ) + { + return new( p ) T( val ); + } + void destroy( pointer p ) + { + p->T::~T(); + } + + // Rebinding allocator to other type + template + struct rebind { + typedef MichaelAllocator other; + }; + }; +} // namespace memory + +#endif // #ifndef CDSSTRESS_MICHAEL_ALLOC_H diff --git a/test/stress/lock/win32_lock.h b/test/stress/lock/win32_lock.h new file mode 100644 index 00000000..db57d329 --- /dev/null +++ b/test/stress/lock/win32_lock.h @@ -0,0 +1,71 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSUNIT_LOCK_WIN32_LOCK_H +#define CDSUNIT_LOCK_WIN32_LOCK_H + +#if defined(_WIN32) || defined(_WIN64) +#define NOMINMAX +#include + +#define UNIT_LOCK_WIN_CS + +namespace lock { + namespace win { + // Win32 critical section + class CS { + CRITICAL_SECTION m_cs; + + public: + CS() { ::InitializeCriticalSection( &m_cs ) ; } + ~CS() { ::DeleteCriticalSection( &m_cs ) ; } + + void lock() { ::EnterCriticalSection( &m_cs ) ; } + void unlock() { ::LeaveCriticalSection( &m_cs) ; } + bool try_lock() { return ::TryEnterCriticalSection( &m_cs ) != 0 ; } + }; + + class Mutex { + HANDLE m_hMutex; + public: + + Mutex() { m_hMutex = ::CreateMutex( nullptr, false, nullptr ); } + ~Mutex() { ::CloseHandle( m_hMutex ) ; } + + void lock() { ::WaitForSingleObject( m_hMutex, INFINITE ); } + void unlock() { ::ReleaseMutex( m_hMutex ); } + bool try_lock() { return ::WaitForSingleObject( m_hMutex, 0) == WAIT_OBJECT_0; } + }; + + } // namespace win +} // namespace lock + +#endif // defined(_WIN32) || defined(_WIN64) +#endif // #ifndef CDSUNIT_LOCK_WIN32_LOCK_H diff --git a/test/stress/michael_alloc.h b/test/stress/michael_alloc.h new file mode 100644 index 00000000..ddaed85c --- /dev/null +++ b/test/stress/michael_alloc.h @@ -0,0 +1,95 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSUNIT_MICHAEL_ALLOC_H +#define CDSUNIT_MICHAEL_ALLOC_H + +#include +#include + +namespace memory { + + typedef cds::memory::michael::Heap< + cds::memory::michael::opt::check_bounds< cds::memory::michael::debug_bound_checking > + > michael_heap; + extern michael_heap s_MichaelHeap; + + template + class MichaelAllocator + { + typedef std::allocator std_allocator; + public: + // Declare typedefs from std::allocator + typedef typename std_allocator::const_pointer const_pointer; + typedef typename std_allocator::pointer pointer; + typedef typename std_allocator::const_reference const_reference; + typedef typename std_allocator::reference reference; + typedef typename std_allocator::difference_type difference_type; + typedef typename std_allocator::size_type size_type; + typedef typename std_allocator::value_type value_type; + + // Allocation function + pointer allocate( size_type _Count, const void* /*_Hint*/ = nullptr ) + { + return reinterpret_cast( s_MichaelHeap.alloc( sizeof(T) * _Count )); + } + + // Deallocation function + void deallocate( pointer _Ptr, size_type /*_Count*/ ) + { + s_MichaelHeap.free( _Ptr ); + } + + pointer address( reference r ) const + { + return &r; + } + const_pointer address( const_reference r ) const + { + return &r; + } + void construct( pointer p, const T& val ) + { + return new( p ) T( val ); + } + void destroy( pointer p ) + { + p->T::~T(); + } + + // Rebinding allocator to other type + template + struct rebind { + typedef MichaelAllocator other; + }; + }; +} // namespace memory + +#endif // #ifndef CDSUNIT_MICHAEL_ALLOC_H diff --git a/test/stress/queue/CMakeLists.txt b/test/stress/queue/CMakeLists.txt new file mode 100644 index 00000000..cca5e7b2 --- /dev/null +++ b/test/stress/queue/CMakeLists.txt @@ -0,0 +1,26 @@ +set(PACKAGE_NAME stress-queue) + +set(CDSSTRESS_QUEUE_SOURCES + ../main.cpp + bounded_queue_fulness.cpp + intrusive_push_pop.cpp + pop.cpp + push.cpp + push_pop.cpp + random.cpp +) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_executable(${PACKAGE_NAME} ${CDSSTRESS_QUEUE_SOURCES} $) +target_link_libraries(${PACKAGE_NAME} + ${CDS_SHARED_LIBRARY} + ${GTEST_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} +) + +add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) \ No newline at end of file diff --git a/test/stress/queue/bounded_queue_fulness.cpp b/test/stress/queue/bounded_queue_fulness.cpp new file mode 100644 index 00000000..16775127 --- /dev/null +++ b/test/stress/queue/bounded_queue_fulness.cpp @@ -0,0 +1,162 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "queue_type.h" + + +/* + Bounded queue test. + The test checks the behaviour of bounded queue when it is almost full. + Many algorithms says the queue is full when it is not, and vice versa. +*/ +namespace { + + static size_t s_nThreadCount = 8; + static size_t s_nQueueSize = 1024; + static size_t s_nPassCount = 1000000; + + class bounded_queue_fulness: public cds_test::stress_fixture + { + typedef cds_test::stress_fixture base_class; + + protected: + template + class Strain: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Queue& m_Queue; + size_t m_nPushError = 0; + size_t m_nPopError = 0; + + public: + Strain( cds_test::thread_pool& pool, Queue& q ) + : base_class( pool ) + , m_Queue( q ) + {} + + Strain( Strain& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + {} + + virtual thread * clone() + { + return new Strain( *this ); + } + + virtual void test() + { + for ( size_t i = 0; i < s_nPassCount; ++i ) { + if ( !m_Queue.push( i )) + ++m_nPushError; + size_t item; + if ( !m_Queue.pop( item )) + ++m_nPopError; + } + } + }; + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "bounded_queue_fulness" ); + + s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + s_nPassCount = cfg.get_size_t( "PassCount", s_nPassCount ); + + if ( s_nThreadCount == 0 ) + s_nThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1024; + if ( s_nPassCount == 0 ) + s_nPassCount = 1; + } + + //static void TearDownTestCase(); + + protected: + template + void analyze( Queue& q ) + { + cds_test::thread_pool& pool = get_pool(); + + size_t nPushError = 0; + size_t nPopError = 0; + for ( size_t i = 0; i < pool.size(); ++i ) { + Strain& strain = static_cast &>(pool.get( i )); + nPushError += strain.m_nPushError; + nPopError += strain.m_nPopError; + } + EXPECT_TRUE( !q.empty()); + EXPECT_EQ( nPushError, 0 ); + EXPECT_EQ( nPopError, 0 ); + } + + template + void test( Queue& q ) + { + cds_test::thread_pool& pool = get_pool(); + pool.add( new Strain( pool, q ), s_nThreadCount ); + + size_t nSize = q.capacity() - s_nThreadCount; + for ( size_t i = 0; i < nSize; ++i ) + q.push( i ); + + propout() << std::make_pair( "thread_count", s_nThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ) + << std::make_pair( "pass_count", s_nPassCount ); + + std::chrono::milliseconds duration = pool.run(); + propout() << std::make_pair( "duration", duration ); + + analyze( q ); + + propout() << q.statistics(); + } + }; + +#undef CDSSTRESS_Queue_F +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< size_t >::type_name queue_type; \ + queue_type queue( s_nQueueSize ); \ + test( queue ); \ + } + + CDSSTRESS_TsigasQueue( bounded_queue_fulness ) + CDSSTRESS_VyukovQueue( bounded_queue_fulness ) + +#undef CDSSTRESS_Queue_F + +} // namespace queue diff --git a/test/stress/queue/intrusive_push_pop.cpp b/test/stress/queue/intrusive_push_pop.cpp new file mode 100644 index 00000000..35d705ed --- /dev/null +++ b/test/stress/queue/intrusive_push_pop.cpp @@ -0,0 +1,583 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "intrusive_queue_type.h" +#include +#include + +// Multi-threaded random queue test +namespace { + + static size_t s_nReaderThreadCount = 4; + static size_t s_nWriterThreadCount = 4; + static size_t s_nQueueSize = 4000000; + + static unsigned int s_nFCPassCount = 8; + static unsigned int s_nFCCompactFactor = 64; + + static atomics::atomic< size_t > s_nProducerCount(0); + static size_t s_nThreadPushCount; + static CDS_CONSTEXPR const size_t c_nBadConsumer = 0xbadc0ffe; + + struct empty {}; + + template + struct value_type: public Base + { + size_t nNo; + size_t nWriterNo; + size_t nConsumer; + }; + + class intrusive_queue_push_pop: public cds_test::stress_fixture + { + typedef cds_test::stress_fixture base_class; + + protected: + enum { + producer_thread, + consumer_thread + }; + + template + class Producer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Producer( cds_test::thread_pool& pool, Queue& q ) + : base_class( pool, producer_thread ) + , m_Queue( q ) + {} + Producer( Producer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + {} + + virtual thread * clone() + { + return new Producer( *this ); + } + + virtual void test() + { + size_t i = 0; + for ( typename Queue::value_type * p = m_pStart; p < m_pEnd; ) { + p->nNo = i; + p->nWriterNo = id(); + CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( &p->nWriterNo ); + if ( m_Queue.push( *p )) { + ++p; + ++i; + } + else + ++m_nPushFailed; + } + s_nProducerCount.fetch_sub( 1, atomics::memory_order_release ); + } + + public: + Queue& m_Queue; + size_t m_nPushFailed = 0; + + // Interval in m_arrValue + typename Queue::value_type * m_pStart; + typename Queue::value_type * m_pEnd; + }; + + template + class Consumer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Queue& m_Queue; + size_t m_nPopEmpty = 0; + size_t m_nPopped = 0; + size_t m_nBadWriter = 0; + + typedef std::vector TPoppedData; + typedef std::vector::iterator data_iterator; + typedef std::vector::const_iterator const_data_iterator; + + std::vector m_WriterData; + + private: + void initPoppedData() + { + const size_t nWriterCount = s_nWriterThreadCount; + const size_t nWriterPushCount = s_nThreadPushCount; + m_WriterData.resize( nWriterCount ); + for ( size_t i = 0; i < nWriterCount; ++i ) + m_WriterData[i].reserve( nWriterPushCount ); + } + + public: + Consumer( cds_test::thread_pool& pool, Queue& q ) + : base_class( pool, consumer_thread ) + , m_Queue( q ) + { + initPoppedData(); + } + Consumer( Consumer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + { + initPoppedData(); + } + + virtual thread * clone() + { + return new Consumer( *this ); + } + + virtual void test() + { + size_t const nTotalWriters = s_nWriterThreadCount; + + while ( true ) { + typename Queue::value_type * p = m_Queue.pop(); + if ( p ) { + p->nConsumer = id(); + ++m_nPopped; + CDS_TSAN_ANNOTATE_HAPPENS_AFTER( &p->nWriterNo ); + if ( p->nWriterNo < nTotalWriters ) + m_WriterData[ p->nWriterNo ].push_back( p->nNo ); + else + ++m_nBadWriter; + } + else { + ++m_nPopEmpty; + if ( s_nProducerCount.load( atomics::memory_order_acquire ) == 0 && m_Queue.empty() ) + break; + } + } + } + }; + + template + class value_array + { + std::unique_ptr m_pArr; + public: + value_array( size_t nSize ) + : m_pArr( new T[nSize] ) + {} + + T * get() const { return m_pArr.get(); } + }; + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "queue_random" ); + + s_nReaderThreadCount = cfg.get_size_t( "ReaderCount", s_nReaderThreadCount ); + s_nWriterThreadCount = cfg.get_size_t( "WriterCount", s_nWriterThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + + s_nFCPassCount = cfg.get_uint( "FCPassCount", s_nFCPassCount ); + s_nFCCompactFactor = cfg.get_uint( "FCCompactFactor", s_nFCCompactFactor ); + + if ( s_nReaderThreadCount == 0 ) + s_nReaderThreadCount = 1; + if ( s_nWriterThreadCount == 0 ) + s_nWriterThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1000; + } + + //static void TearDownTestCase(); + + protected: + template + void analyze( Queue& testQueue, size_t /*nLeftOffset*/, size_t nRightOffset ) + { + typedef Consumer Reader; + typedef Producer Writer; + typedef typename Reader::const_data_iterator ReaderIterator; + + size_t nPostTestPops = 0; + while ( testQueue.pop() ) + ++nPostTestPops; + + size_t nTotalPops = 0; + size_t nPopFalse = 0; + size_t nPoppedItems = 0; + size_t nPushFailed = 0; + + std::vector< Reader * > arrReaders; + + cds_test::thread_pool& pool = get_pool(); + for ( size_t i = 0; i < pool.size(); ++i ) { + cds_test::thread& thr = pool.get( i ); + if ( thr.type() == consumer_thread ) { + Consumer& consumer = static_cast&>( thr ); + nTotalPops += consumer.m_nPopped; + nPopFalse += consumer.m_nPopEmpty; + arrReaders.push_back( &consumer ); + EXPECT_EQ( consumer.m_nBadWriter, 0 ) << "consumer " << (i - s_nWriterThreadCount); + + size_t nPopped = 0; + for ( size_t n = 0; n < s_nWriterThreadCount; ++n ) + nPopped += consumer.m_WriterData[n].size(); + + { + std::stringstream s; + s << "consumer" << (i - s_nWriterThreadCount) << "_popped"; + propout() << std::make_pair( s.str().c_str(), nPopped ); + } + nPoppedItems += nPopped; + } + else { + Producer& producer = static_cast&>( thr ); + nPushFailed += producer.m_nPushFailed; + if ( !std::is_base_of::value ) { + EXPECT_EQ( producer.m_nPushFailed, 0 ) << "producer " << i; + } + } + } + EXPECT_EQ( nTotalPops, nPoppedItems ); + + propout() << std::make_pair( "success_pop", nTotalPops ) + << std::make_pair( "empty_pop", nPopFalse ) + << std::make_pair( "failed_push", nPushFailed ); + + size_t nQueueSize = s_nThreadPushCount * s_nWriterThreadCount; + EXPECT_EQ( nTotalPops + nPostTestPops, nQueueSize ); + EXPECT_TRUE( testQueue.empty() ); + + // Test that all items have been popped + // Test FIFO order + for ( size_t nWriter = 0; nWriter < s_nWriterThreadCount; ++nWriter ) { + std::vector arrData; + arrData.reserve( s_nThreadPushCount ); + for ( size_t nReader = 0; nReader < arrReaders.size(); ++nReader ) { + ReaderIterator it = arrReaders[nReader]->m_WriterData[nWriter].begin(); + ReaderIterator itEnd = arrReaders[nReader]->m_WriterData[nWriter].end(); + if ( it != itEnd ) { + ReaderIterator itPrev = it; + for ( ++it; it != itEnd; ++it ) { + EXPECT_LT( *itPrev, *it + nRightOffset ) + << "Reader " << nReader << ", Writer " << nWriter << ": prev=" << *itPrev << ", cur=" << *it; + itPrev = it; + } + } + + for ( it = arrReaders[nReader]->m_WriterData[nWriter].begin(); it != itEnd; ++it ) + arrData.push_back( *it ); + } + std::sort( arrData.begin(), arrData.end() ); + for ( size_t i=1; i < arrData.size(); ++i ) { + if ( arrData[i-1] + 1 != arrData[i] ) { + EXPECT_EQ( arrData[i-1] + 1, arrData[i] ) << "Writer " << nWriter << ": [" << (i-1) << "]=" << arrData[i-1] + << ", [" << i << "]=" << arrData[i]; + } + } + + EXPECT_EQ( arrData[0], 0 ) << "Writer " << nWriter; + EXPECT_EQ( arrData[arrData.size() - 1], s_nThreadPushCount - 1 ) << "Writer " << nWriter; + } + } + + template + void test( Queue& q, value_array& arrValue, size_t nLeftOffset, size_t nRightOffset ) + { + s_nThreadPushCount = s_nQueueSize / s_nWriterThreadCount; + s_nQueueSize = s_nThreadPushCount * s_nWriterThreadCount; + propout() << std::make_pair( "producer_count", s_nWriterThreadCount ) + << std::make_pair( "consumer_count", s_nReaderThreadCount ) + << std::make_pair( "queue_size", s_nQueueSize ); + + typename Queue::value_type * pValStart = arrValue.get(); + typename Queue::value_type * pValEnd = pValStart + s_nQueueSize; + + cds_test::thread_pool& pool = get_pool(); + s_nProducerCount.store( s_nWriterThreadCount, atomics::memory_order_release ); + + // Writers must be first + pool.add( new Producer( pool, q ), s_nWriterThreadCount ); + { + for ( typename Queue::value_type * it = pValStart; it != pValEnd; ++it ) { + it->nNo = 0; + it->nWriterNo = 0; + it->nConsumer = c_nBadConsumer; + } + + typename Queue::value_type * pStart = pValStart; + for ( size_t i = 0; i < pool.size(); ++i ) { + Producer& producer = static_cast&>( pool.get( i )); + producer.m_pStart = pStart; + pStart += s_nThreadPushCount; + producer.m_pEnd = pStart; + } + } + pool.add( new Consumer( pool, q ), s_nReaderThreadCount ); + + std::chrono::milliseconds duration = pool.run(); + propout() << std::make_pair( "duration", duration ); + + // Check that all values have been dequeued + { + size_t nBadConsumerCount = 0; + typename Queue::value_type * pEnd = pValStart + s_nQueueSize; + for ( typename Queue::value_type * it = pValStart; it != pEnd; ++it ) { + if ( it->nConsumer == c_nBadConsumer ) + ++nBadConsumerCount; + } + EXPECT_EQ( nBadConsumerCount, 0 ); + } + + analyze( q, nLeftOffset, nRightOffset ); + + propout() << q.statistics(); + } + +/* + template + void test( Queue& q ) + { + value_array arrValue( s_nQueueSize ); + { + { + Queue q; + test_with( q, arrValue, 0, 0 ); + } + Queue::gc::force_dispose(); + } + } + + template + void test_boost() + { + value_array arrValue( s_nQueueSize ); + { + Queue q; + test_with(q, arrValue, 0, 0); + } + } + + template + void test_bounded() + { + value_array arrValue( s_nQueueSize ); + Queue q; + test_with(q, arrValue, 0, 0); + } + + template + void test_fcqueue() + { + value_array arrValue( s_nQueueSize ); + CPPUNIT_MSG( "Combining pass count: " << s_nFCPassCount << ", compact factor: " << s_nFCCompactFactor ); + Queue q( s_nFCCompactFactor, s_nFCPassCount ); + test_with(q, arrValue, 0, 0); + } + + template + void test_segmented() + { + value_array arrValue( s_nQueueSize ); + for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { + CPPUNIT_MSG( "Segment size: " << nSegmentSize ); + { + Queue q( nSegmentSize ); + test_with( q, arrValue, nSegmentSize * 2, nSegmentSize ); + } + Queue::gc::force_dispose(); + } + } + + template + void test_spqueue() + { + value_array arrValue( s_nQueueSize ); + for ( size_t nArraySize = 2; nArraySize <= 64; nArraySize *= 2 ) { + CPPUNIT_MSG( "Array size: " << nArraySize ); + { + Queue q( nArraySize ); + test_with( q, arrValue, 0, 0 ); + } + Queue::gc::force_dispose(); + } + } +*/ + }; + +#define CDSSTRESS_QUEUE_F( QueueType, NodeType ) \ + TEST_F( intrusive_queue_push_pop, QueueType ) \ + { \ + typedef value_type node_type; \ + typedef typename queue::Types< node_type >::QueueType queue_type; \ + value_array arrValue( s_nQueueSize ); \ + { \ + queue_type q; \ + test( q, arrValue, 0, 0 ); \ + } \ + queue_type::gc::force_dispose(); \ + } + + CDSSTRESS_QUEUE_F( MSQueue_HP, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MSQueue_HP_ic, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MSQueue_HP_stat, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MSQueue_DHP, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MSQueue_DHP_ic, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MSQueue_DHP_stat, cds::intrusive::msqueue::node ) + + CDSSTRESS_QUEUE_F( MoirQueue_HP, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MoirQueue_HP_ic, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MoirQueue_HP_stat, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MoirQueue_DHP, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MoirQueue_DHP_ic, cds::intrusive::msqueue::node ) + CDSSTRESS_QUEUE_F( MoirQueue_DHP_stat, cds::intrusive::msqueue::node ) + + CDSSTRESS_QUEUE_F( OptimisticQueue_HP, cds::intrusive::optimistic_queue::node ) + CDSSTRESS_QUEUE_F( OptimisticQueue_HP_ic, cds::intrusive::optimistic_queue::node ) + CDSSTRESS_QUEUE_F( OptimisticQueue_HP_stat, cds::intrusive::optimistic_queue::node ) + CDSSTRESS_QUEUE_F( OptimisticQueue_DHP, cds::intrusive::optimistic_queue::node ) + CDSSTRESS_QUEUE_F( OptimisticQueue_DHP_ic, cds::intrusive::optimistic_queue::node ) + CDSSTRESS_QUEUE_F( OptimisticQueue_DHP_stat, cds::intrusive::optimistic_queue::node ) + + CDSSTRESS_QUEUE_F( BasketQueue_HP, cds::intrusive::basket_queue::node ) + CDSSTRESS_QUEUE_F( BasketQueue_HP_ic, cds::intrusive::basket_queue::node ) + CDSSTRESS_QUEUE_F( BasketQueue_HP_stat, cds::intrusive::basket_queue::node ) + CDSSTRESS_QUEUE_F( BasketQueue_DHP, cds::intrusive::basket_queue::node ) + CDSSTRESS_QUEUE_F( BasketQueue_DHP_ic, cds::intrusive::basket_queue::node ) + CDSSTRESS_QUEUE_F( BasketQueue_DHP_stat, cds::intrusive::basket_queue::node ) +#undef CDSSTRESS_QUEUE_F + + +#define CDSSTRESS_QUEUE_F( QueueType, NodeType ) \ + TEST_F( intrusive_queue_push_pop, QueueType ) \ + { \ + typedef value_type node_type; \ + typedef typename queue::Types< node_type >::QueueType queue_type; \ + value_array arrValue( s_nQueueSize ); \ + queue_type q( s_nFCCompactFactor, s_nFCPassCount ); \ + test( q, arrValue, 0, 0 ); \ + } + + CDSSTRESS_QUEUE_F(FCQueue_list_delay2, boost::intrusive::list_base_hook<> ) + CDSSTRESS_QUEUE_F(FCQueue_list_delay2_elimination, boost::intrusive::list_base_hook<> ) + CDSSTRESS_QUEUE_F(FCQueue_list_delay2_elimination_stat, boost::intrusive::list_base_hook<> ) + CDSSTRESS_QUEUE_F(FCQueue_list_expbackoff_elimination, boost::intrusive::list_base_hook<> ) + CDSSTRESS_QUEUE_F(FCQueue_list_expbackoff_elimination_stat, boost::intrusive::list_base_hook<> ) +#undef CDSSTRESS_QUEUE_F + + +#define CDSSTRESS_QUEUE_F( QueueType ) \ + TEST_F( intrusive_queue_push_pop, QueueType ) \ + { \ + typedef typename queue::Types< value_type<> >::QueueType queue_type; \ + value_array arrValue( s_nQueueSize ); \ + queue_type q( s_nQueueSize ); \ + test( q, arrValue, 0, 0 ); \ + } + + CDSSTRESS_QUEUE_F( TsigasCycleQueue_dyn ) + CDSSTRESS_QUEUE_F( TsigasCycleQueue_dyn_ic ) + CDSSTRESS_QUEUE_F( VyukovMPMCCycleQueue_dyn ) + CDSSTRESS_QUEUE_F( VyukovMPMCCycleQueue_dyn_ic ) +#undef CDSSTRESS_QUEUE_F + + + // ******************************************************************** + // SegmentedQueue test + + class intrusive_segmented_queue_push_pop + : public intrusive_queue_push_pop + , public ::testing::WithParamInterface< size_t > + { + typedef intrusive_queue_push_pop base_class; + + protected: + template + void test() + { + value_array arrValue( s_nQueueSize ); \ + { + size_t quasi_factor = GetParam(); + + Queue q( quasi_factor ); + propout() << std::make_pair( "quasi_factor", quasi_factor ); + + base_class::test( q, arrValue, quasi_factor * 2, quasi_factor ); + } + Queue::gc::force_dispose(); + } + + public: + static std::vector< size_t > get_test_parameters() + { + cds_test::config const& cfg = cds_test::stress_fixture::get_config( "intrusive_queue_push_pop" ); + bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false ); + size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 ); + + std::vector args; + if ( bIterative && quasi_factor > 4 ) { + for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 ) + args.push_back( qf ); + } + else { + if ( quasi_factor > 2 ) + args.push_back( quasi_factor ); + else + args.push_back( 2 ); + } + + return args; + } + }; + +#define CDSSTRESS_QUEUE_F( type_name ) \ + TEST_P( intrusive_segmented_queue_push_pop, type_name ) \ + { \ + typedef typename queue::Types>::type_name queue_type; \ + test< queue_type >(); \ + } + + CDSSTRESS_QUEUE_F( SegmentedQueue_HP_spin ) + //CDSSTRESS_QUEUE_F( SegmentedQueue_HP_spin_padding ) + CDSSTRESS_QUEUE_F( SegmentedQueue_HP_spin_stat ) + CDSSTRESS_QUEUE_F( SegmentedQueue_HP_mutex ) + //CDSSTRESS_QUEUE_F( SegmentedQueue_HP_mutex_padding ) + CDSSTRESS_QUEUE_F( SegmentedQueue_HP_mutex_stat ) + CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_spin ) + //CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_spin_padding ) + CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_spin_stat ) + CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_mutex ) + //CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_mutex_padding ) + CDSSTRESS_QUEUE_F( SegmentedQueue_DHP_mutex_stat ) + + INSTANTIATE_TEST_CASE_P( SQ, + intrusive_segmented_queue_push_pop, + ::testing::ValuesIn( intrusive_segmented_queue_push_pop::get_test_parameters() ) ); + +} // namespace diff --git a/tests/unit/queue/intrusive_queue_type.h b/test/stress/queue/intrusive_queue_type.h similarity index 80% rename from tests/unit/queue/intrusive_queue_type.h rename to test/stress/queue/intrusive_queue_type.h index 4bf1a920..d6f48368 100644 --- a/tests/unit/queue/intrusive_queue_type.h +++ b/test/stress/queue/intrusive_queue_type.h @@ -28,8 +28,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CDSUNIT_INTRUSIVE_QUEUE_TYPES_H -#define CDSUNIT_INTRUSIVE_QUEUE_TYPES_H +#ifndef CDSSTRESS_INTRUSIVE_QUEUE_TYPES_H +#define CDSSTRESS_INTRUSIVE_QUEUE_TYPES_H #include #include @@ -45,7 +45,8 @@ #include -#include "print_segmentedqueue_stat.h" +#include +#include "print_stat.h" namespace queue { @@ -108,11 +109,11 @@ namespace queue { return empty_stat(); } }; - } + } // namespace details template - struct Types { - + struct Types + { // MSQueue, MoirQueue struct traits_MSQueue_HP : public cds::intrusive::msqueue::traits { @@ -494,127 +495,36 @@ namespace queue { typedef details::BoostSList< T, std::mutex > BoostSList_mutex; typedef details::BoostSList< T, cds::sync::spin > BoostSList_spin; }; -} - - -// ********************************************* -// Queue statistics -namespace std { - /* - // cds::intrusive::queue_stat - template - static inline std::ostream& operator <<(std::ostream& o, cds::intrusive::queue_stat const& s) - { - return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\tAdvance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n"; - } - static inline std::ostream& operator <<(std::ostream& o, cds::intrusive::queue_dummy_stat const& s) - { - return o; - } - */ +} // namespace queue +namespace cds_test { + // cds::container::fcqueue::stat template - static inline std::ostream& operator <<(std::ostream& o, cds::intrusive::basket_queue::stat const& s) + static inline property_stream& operator <<( property_stream& o, cds::intrusive::fcqueue::stat const& s ) { return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\t Advance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n" - << "\t\tAdd basket attempts: " << s.m_TryAddBasket.get() << "\n" - << "\t\t Add basket success: " << s.m_AddBasketCount.get() << "\n"; - } - static inline std::ostream& operator <<(std::ostream& o, cds::intrusive::basket_queue::empty_stat const& /*s*/) - { - return o; - } - - template - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::msqueue::stat const& s ) - { - return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\tAdvance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n"; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::msqueue::empty_stat const& /*s*/ ) - { - return o; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::opt::none ) - { - return o; - } - - // cds::intrusive::optimistic_queue::stat - template - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::optimistic_queue::stat const& s ) - { - return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\tAdvance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n" - << "\t\t fix list call: " << s.m_FixListCount.get() << "\n"; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::optimistic_queue::empty_stat const& /*s*/ ) - { - return o; - } - - // cds::intrusive::fcqueue::stat - template - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::fcqueue::stat const& s ) - { - return o << "\tStatistics:\n" - << "\t Push: " << s.m_nEnqueue.get() << "\n" - << "\t Pop: " << s.m_nDequeue.get() << "\n" - << "\t FailedPop: " << s.m_nFailedDeq.get() << "\n" - << "\t Collided push/pop pair: " << s.m_nCollided.get() << "\n" - << "\tFlat combining statistics:\n" - << "\t Combining factor: " << s.combining_factor() << "\n" - << "\t Operation count: " << s.m_nOperationCount.get() << "\n" - << "\t Combine call count: " << s.m_nCombiningCount.get() << "\n" - << "\t Compact pub-list: " << s.m_nCompactPublicationList.get() << "\n" - << "\t Deactivate pub-record: " << s.m_nDeactivatePubRecord.get() << "\n" - << "\t Activate pub-record: " << s.m_nActivatePubRecord.get() << "\n" - << "\t Create pub-record: " << s.m_nPubRecordCreated.get() << "\n" - << "\t Delete pub-record: " << s.m_nPubRecordDeteted.get() << "\n" - << "\t Acquire pub-record: " << s.m_nAcquirePubRecCount.get()<< "\n" - << "\t Release pub-record: " << s.m_nReleasePubRecCount.get()<< "\n"; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::fcqueue::empty_stat const& /*s*/ ) - { - return o; + << CDSSTRESS_STAT_OUT( s, m_nEnqueue ) + << CDSSTRESS_STAT_OUT( s, m_nDequeue ) + << CDSSTRESS_STAT_OUT( s, m_nFailedDeq ) + << CDSSTRESS_STAT_OUT( s, m_nCollided ) + << CDSSTRESS_STAT_OUT_( "combining_factor", s.combining_factor() ) + << CDSSTRESS_STAT_OUT( s, m_nOperationCount ) + << CDSSTRESS_STAT_OUT( s, m_nCombiningCount ) + << CDSSTRESS_STAT_OUT( s, m_nCompactPublicationList ) + << CDSSTRESS_STAT_OUT( s, m_nDeactivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nActivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordCreated ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordDeteted ) + << CDSSTRESS_STAT_OUT( s, m_nAcquirePubRecCount ) + << CDSSTRESS_STAT_OUT( s, m_nReleasePubRecCount ); } - static inline std::ostream& operator <<( std::ostream& o, queue::details::empty_stat const& /*s*/ ) + static inline property_stream& operator <<( property_stream& o, cds::intrusive::fcqueue::empty_stat const& /*s*/ ) { return o; } -} // namespace std +} // namespace cds_test -#endif // #ifndef CDSUNIT_INTRUSIVE_QUEUE_TYPES_H +#endif // #ifndef CDSSTRESS_INTRUSIVE_QUEUE_TYPES_H diff --git a/test/stress/queue/pop.cpp b/test/stress/queue/pop.cpp new file mode 100644 index 00000000..d77cd4e5 --- /dev/null +++ b/test/stress/queue/pop.cpp @@ -0,0 +1,249 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "queue_type.h" + +// Multi-threaded queue test for pop operation +namespace { + + static size_t s_nThreadCount = 8; + static size_t s_nQueueSize = 20000000 ; // no more than 20 million records + + struct SimpleValue { + size_t nNo; + + SimpleValue(): nNo(0) {} + SimpleValue( size_t n ): nNo(n) {} + size_t getNo() const { return nNo; } + }; + + class queue_pop: public cds_test::stress_fixture + { + protected: + struct value_type + { + size_t nNo; + + value_type() + : nNo( 0 ) + {} + + value_type( size_t n ) + : nNo( n ) + {} + }; + + template + class Consumer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Consumer( cds_test::thread_pool& pool, Queue& queue ) + : base_class( pool ) + , m_Queue( queue ) + , m_arr( new uint8_t[ s_nQueueSize ]) + , m_nPopCount( 0 ) + {} + + Consumer( Consumer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + , m_arr( new uint8_t[ s_nQueueSize ]) + , m_nPopCount( 0 ) + {} + + virtual thread * clone() + { + return new Consumer( *this ); + } + + virtual void test() + { + memset( m_arr.get(), 0, sizeof( m_arr[0] ) * s_nQueueSize ); + typedef typename Queue::value_type value_type; + value_type value; + size_t nPopCount = 0; + while ( m_Queue.pop( value ) ) { + ++m_arr[ value.nNo ]; + ++nPopCount; + } + m_nPopCount = nPopCount; + } + + public: + Queue& m_Queue; + std::unique_ptr< uint8_t[] > m_arr; + size_t m_nPopCount; + }; + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "queue_pop" ); + + s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + + if ( s_nThreadCount == 0 ) + s_nThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1000; + } + + //static void TearDownTestCase(); + + protected: + template + void analyze( Queue& q ) + { + cds_test::thread_pool& pool = get_pool(); + std::unique_ptr< uint8_t[] > arr( new uint8_t[s_nQueueSize] ); + memset(arr.get(), 0, sizeof(arr[0]) * s_nQueueSize ); + + size_t nTotalPops = 0; + for ( size_t i = 0; i < pool.size(); ++i ) { + Consumer& thread = static_cast&>(pool.get( i )); + for ( size_t i = 0; i < s_nQueueSize; ++i ) + arr[i] += thread.m_arr[i]; + nTotalPops += thread.m_nPopCount; + } + EXPECT_EQ( nTotalPops, s_nQueueSize ); + EXPECT_TRUE( q.empty()); + + for ( size_t i = 0; i < s_nQueueSize; ++i ) { + EXPECT_EQ( arr[i], 1 ) << "i=" << i; + } + } + + template + void test( Queue& q ) + { + cds_test::thread_pool& pool = get_pool(); + + pool.add( new Consumer( pool, q ), s_nThreadCount ); + + for ( size_t i = 0; i < s_nQueueSize; ++i ) + q.push( i ); + + propout() << std::make_pair( "thread_count", s_nThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ); + + std::chrono::milliseconds duration = pool.run(); + + propout() << std::make_pair( "duration", duration ); + + analyze( q ); + + propout() << q.statistics(); + } + }; + + CDSSTRESS_MSQueue( queue_pop ) + CDSSTRESS_MoirQueue( queue_pop ) + CDSSTRESS_BasketQueue( queue_pop ) + CDSSTRESS_OptimsticQueue( queue_pop ) + CDSSTRESS_FCQueue( queue_pop ) + CDSSTRESS_FCDeque( queue_pop ) + CDSSTRESS_RWQueue( queue_pop ) + CDSSTRESS_StdQueue( queue_pop ) + +#undef CDSSTRESS_Queue_F +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< value_type >::type_name queue_type; \ + queue_type queue( s_nQueueSize ); \ + test( queue ); \ + } + + CDSSTRESS_TsigasQueue( queue_pop ) + CDSSTRESS_VyukovQueue( queue_pop ) + +#undef CDSSTRESS_Queue_F + + + // ******************************************************************** + // SegmentedQueue test + + class segmented_queue_pop + : public queue_pop + , public ::testing::WithParamInterface< size_t > + { + typedef queue_pop base_class; + + protected: + template + void test() + { + size_t quasi_factor = GetParam(); + + Queue q( quasi_factor ); + propout() << std::make_pair( "quasi_factor", quasi_factor ); + base_class::test( q ); + } + + public: + static std::vector< size_t > get_test_parameters() + { + cds_test::config const& cfg = cds_test::stress_fixture::get_config( "queue_pop" ); + bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false ); + size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 ); + + std::vector args; + if ( bIterative && quasi_factor > 4 ) { + for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 ) + args.push_back( qf ); + } + else { + if ( quasi_factor > 2 ) + args.push_back( quasi_factor ); + else + args.push_back( 2 ); + } + + return args; + } + }; + +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_P( test_fixture, type_name ) \ + { \ + typedef typename queue::Types::type_name queue_type; \ + test< queue_type >(); \ + } + + CDSSTRESS_SegmentedQueue( segmented_queue_pop ) + + INSTANTIATE_TEST_CASE_P( SQ, + segmented_queue_pop, + ::testing::ValuesIn( segmented_queue_pop::get_test_parameters())); + +} // namespace diff --git a/test/stress/queue/print_stat.h b/test/stress/queue/print_stat.h new file mode 100644 index 00000000..267dfeaf --- /dev/null +++ b/test/stress/queue/print_stat.h @@ -0,0 +1,125 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CDSSTRESS_QUEUE_PRINT_STAT_H +#define CDSSTRESS_QUEUE_PRINT_STAT_H + +namespace cds_test { + + template + static inline property_stream& operator <<( property_stream& o, cds::intrusive::basket_queue::stat const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_EnqueueCount ) + << CDSSTRESS_STAT_OUT( s, m_EnqueueRace ) + << CDSSTRESS_STAT_OUT( s, m_DequeueCount ) + << CDSSTRESS_STAT_OUT( s, m_EmptyDequeue ) + << CDSSTRESS_STAT_OUT( s, m_DequeueRace ) + << CDSSTRESS_STAT_OUT( s, m_AdvanceTailError ) + << CDSSTRESS_STAT_OUT( s, m_BadTail ) + << CDSSTRESS_STAT_OUT( s, m_TryAddBasket ) + << CDSSTRESS_STAT_OUT( s, m_AddBasketCount ); + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::basket_queue::empty_stat const& /*s*/ ) + { + return o; + } + + template + static inline property_stream& operator <<( property_stream& o, cds::intrusive::msqueue::stat const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_EnqueueCount ) + << CDSSTRESS_STAT_OUT( s, m_EnqueueRace ) + << CDSSTRESS_STAT_OUT( s, m_DequeueCount ) + << CDSSTRESS_STAT_OUT( s, m_EmptyDequeue ) + << CDSSTRESS_STAT_OUT( s, m_DequeueRace ) + << CDSSTRESS_STAT_OUT( s, m_AdvanceTailError ) + << CDSSTRESS_STAT_OUT( s, m_BadTail ); + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::msqueue::empty_stat const& /*s*/ ) + { + return o; + } + + static inline property_stream& operator <<( property_stream& o, cds::opt::none ) + { + return o; + } + + template + static inline property_stream& operator <<( property_stream& o, cds::intrusive::optimistic_queue::stat const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_EnqueueCount ) + << CDSSTRESS_STAT_OUT( s, m_EnqueueRace ) + << CDSSTRESS_STAT_OUT( s, m_DequeueCount ) + << CDSSTRESS_STAT_OUT( s, m_EmptyDequeue ) + << CDSSTRESS_STAT_OUT( s, m_DequeueRace ) + << CDSSTRESS_STAT_OUT( s, m_AdvanceTailError ) + << CDSSTRESS_STAT_OUT( s, m_BadTail ) + << CDSSTRESS_STAT_OUT( s, m_FixListCount ); + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::optimistic_queue::empty_stat const& /*s*/ ) + { + return o; + } + + static inline property_stream& operator <<( property_stream& o, std::nullptr_t /*s*/ ) + { + return o; + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::segmented_queue::stat<> const& s ) + { + return o + << CDSSTRESS_STAT_OUT( s, m_nPush ) + << CDSSTRESS_STAT_OUT( s, m_nPushPopulated ) + << CDSSTRESS_STAT_OUT( s, m_nPushContended ) + << CDSSTRESS_STAT_OUT( s, m_nPop ) + << CDSSTRESS_STAT_OUT( s, m_nPopEmpty ) + << CDSSTRESS_STAT_OUT( s, m_nPopContended ) + << CDSSTRESS_STAT_OUT( s, m_nCreateSegmentReq ) + << CDSSTRESS_STAT_OUT( s, m_nDeleteSegmentReq ) + << CDSSTRESS_STAT_OUT( s, m_nSegmentCreated ) + << CDSSTRESS_STAT_OUT( s, m_nSegmentDeleted ); + } + + static inline property_stream& operator <<( property_stream& o, cds::intrusive::segmented_queue::empty_stat const& /*s*/ ) + { + return o; + } + +} // namespace cds_test + +#endif // CDSSTRESS_QUEUE_PRINT_STAT_H diff --git a/test/stress/queue/push.cpp b/test/stress/queue/push.cpp new file mode 100644 index 00000000..fc205b93 --- /dev/null +++ b/test/stress/queue/push.cpp @@ -0,0 +1,252 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "queue_type.h" + +// Multi-threaded queue test for push operation +namespace { + + static size_t s_nThreadCount = 8; + static size_t s_nQueueSize = 20000000 ; // no more than 20 million records + + class queue_push: public cds_test::stress_fixture + { + protected: + struct value_type + { + size_t nNo; + + value_type() + : nNo( 0 ) + {} + + value_type( size_t n ) + : nNo( n ) + {} + }; + + template + class Producer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Producer( cds_test::thread_pool& pool, Queue& queue ) + : base_class( pool ) + , m_Queue( queue ) + , m_nStartItem( 0 ) + , m_nEndItem( 0 ) + , m_nPushError( 0 ) + {} + + Producer( Producer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + , m_nStartItem( 0 ) + , m_nEndItem( 0 ) + , m_nPushError( 0 ) + {} + + virtual thread * clone() + { + return new Producer( *this ); + } + + virtual void test() + { + for ( size_t nItem = m_nStartItem; nItem < m_nEndItem; ++nItem ) { + if ( !m_Queue.push( nItem )) + ++m_nPushError; + } + } + + public: + Queue& m_Queue; + size_t m_nStartItem; + size_t m_nEndItem; + size_t m_nPushError; + }; + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "queue_push" ); + + s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + + if ( s_nThreadCount == 0 ) + s_nThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1000; + } + + //static void TearDownTestCase(); + + protected: + template + void test( Queue& q ) + { + cds_test::thread_pool& pool = get_pool(); + + pool.add( new Producer( pool, q ), s_nThreadCount ); + + size_t nStart = 0; + size_t nThreadItemCount = s_nQueueSize / s_nThreadCount; + for ( size_t i = 0; i < pool.size(); ++i ) { + Producer& thread = static_cast&>(pool.get( i )); + thread.m_nStartItem = nStart; + nStart += nThreadItemCount; + thread.m_nEndItem = nStart; + } + + s_nQueueSize = nThreadItemCount * s_nThreadCount; + propout() << std::make_pair( "thread_count", s_nThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ); + + std::chrono::milliseconds duration = pool.run(); + + propout() << std::make_pair( "duration", duration ); + + analyze( q ); + + propout() << q.statistics(); + } + + template + void analyze( Queue& q ) + { + size_t nThreadItems = s_nQueueSize / s_nThreadCount; + cds_test::thread_pool& pool = get_pool(); + + for ( size_t i = 0; i < pool.size(); ++i ) { + Producer& thread = static_cast&>(pool.get( i )); + EXPECT_EQ( thread.m_nPushError, 0 ) << " producer thread " << i; + } + EXPECT_TRUE( !q.empty() ); + + std::unique_ptr< uint8_t[] > arr( new uint8_t[s_nQueueSize] ); + memset( arr.get(), 0, sizeof(arr[0]) * s_nQueueSize ); + + size_t nPopped = 0; + value_type val; + while ( q.pop( val )) { + nPopped++; + ++arr[ val.nNo ]; + } + + size_t nTotalItems = nThreadItems * s_nThreadCount; + for ( size_t i = 0; i < nTotalItems; ++i ) { + EXPECT_EQ( arr[i], 1 ) << "i=" << i; + } + } + }; + + CDSSTRESS_MSQueue( queue_push ) + CDSSTRESS_MoirQueue( queue_push ) + CDSSTRESS_BasketQueue( queue_push ) + CDSSTRESS_OptimsticQueue( queue_push ) + CDSSTRESS_FCQueue( queue_push ) + CDSSTRESS_FCDeque( queue_push ) + CDSSTRESS_RWQueue( queue_push ) + CDSSTRESS_StdQueue( queue_push ) + +#undef CDSSTRESS_Queue_F +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< value_type >::type_name queue_type; \ + queue_type queue( s_nQueueSize ); \ + test( queue ); \ + } + + CDSSTRESS_TsigasQueue( queue_push ) + CDSSTRESS_VyukovQueue( queue_push ) + +#undef CDSSTRESS_Queue_F + + + // ******************************************************************** + // SegmentedQueue test + + class segmented_queue_push + : public queue_push + , public ::testing::WithParamInterface< size_t > + { + typedef queue_push base_class; + + protected: + template + void test() + { + size_t quasi_factor = GetParam(); + + Queue q( quasi_factor ); + propout() << std::make_pair( "quasi_factor", quasi_factor ); + base_class::test( q ); + } + + public: + static std::vector< size_t > get_test_parameters() + { + cds_test::config const& cfg = cds_test::stress_fixture::get_config( "queue_push" ); + bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false ); + size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 ); + + std::vector args; + if ( bIterative && quasi_factor > 4 ) { + for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 ) + args.push_back( qf ); + } + else { + if ( quasi_factor > 2 ) + args.push_back( quasi_factor ); + else + args.push_back( 2 ); + } + + return args; + } + }; + +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_P( test_fixture, type_name ) \ + { \ + typedef typename queue::Types::type_name queue_type; \ + test< queue_type >(); \ + } + + CDSSTRESS_SegmentedQueue( segmented_queue_push ) + + INSTANTIATE_TEST_CASE_P( SQ, + segmented_queue_push, + ::testing::ValuesIn( segmented_queue_push::get_test_parameters())); + +} // namespace diff --git a/test/stress/queue/push_pop.cpp b/test/stress/queue/push_pop.cpp new file mode 100644 index 00000000..328a51ec --- /dev/null +++ b/test/stress/queue/push_pop.cpp @@ -0,0 +1,404 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "queue_type.h" + +#include +#include + +// Multi-threaded queue push/pop test +namespace { + + static size_t s_nConsumerThreadCount = 4; + static size_t s_nProducerThreadCount = 4; + static size_t s_nQueueSize = 4000000; + + static std::atomic s_nProducerDone( 0 ); + + class queue_push_pop: public cds_test::stress_fixture + { + protected: + struct value_type + { + size_t nNo; + size_t nWriterNo; + }; + + enum { + producer_thread, + consumer_thread + }; + + template + class Producer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Producer( cds_test::thread_pool& pool, Queue& queue, size_t nPushCount ) + : base_class( pool, producer_thread ) + , m_Queue( queue ) + , m_nPushFailed( 0 ) + , m_nPushCount( nPushCount ) + {} + + Producer( Producer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + , m_nPushFailed( 0 ) + , m_nPushCount( src.m_nPushCount ) + {} + + virtual thread * clone() + { + return new Producer( *this ); + } + + virtual void test() + { + size_t const nPushCount = m_nPushCount; + value_type v; + v.nWriterNo = id(); + v.nNo = 0; + m_nPushFailed = 0; + + while ( v.nNo < nPushCount ) { + if ( m_Queue.push( v )) + ++v.nNo; + else + ++m_nPushFailed; + } + + s_nProducerDone.fetch_add( 1 ); + } + public: + Queue& m_Queue; + size_t m_nPushFailed; + size_t const m_nPushCount; + }; + + template + class Consumer: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Queue& m_Queue; + size_t const m_nPushPerProducer; + size_t m_nPopEmpty; + size_t m_nPopped; + size_t m_nBadWriter; + + typedef std::vector popped_data; + typedef std::vector::iterator data_iterator; + typedef std::vector::const_iterator const_data_iterator; + + std::vector m_WriterData; + + private: + void initPoppedData() + { + const size_t nProducerCount = s_nProducerThreadCount; + m_WriterData.resize( nProducerCount ); + for ( size_t i = 0; i < nProducerCount; ++i ) + m_WriterData[i].reserve( m_nPushPerProducer ); + } + + public: + Consumer( cds_test::thread_pool& pool, Queue& queue, size_t nPushPerProducer ) + : base_class( pool, consumer_thread ) + , m_Queue( queue ) + , m_nPushPerProducer( nPushPerProducer ) + , m_nPopEmpty( 0 ) + , m_nPopped( 0 ) + , m_nBadWriter( 0 ) + { + initPoppedData(); + } + Consumer( Consumer& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + , m_nPushPerProducer( src.m_nPushPerProducer ) + , m_nPopEmpty( 0 ) + , m_nPopped( 0 ) + , m_nBadWriter( 0 ) + { + initPoppedData(); + } + + virtual thread * clone() + { + return new Consumer( *this ); + } + + virtual void test() + { + m_nPopEmpty = 0; + m_nPopped = 0; + m_nBadWriter = 0; + const size_t nTotalWriters = s_nProducerThreadCount; + value_type v; + while ( true ) { + if ( m_Queue.pop( v ) ) { + ++m_nPopped; + if ( v.nWriterNo < nTotalWriters ) + m_WriterData[ v.nWriterNo ].push_back( v.nNo ); + else + ++m_nBadWriter; + } + else + ++m_nPopEmpty; + + if ( m_Queue.empty() ) { + if ( s_nProducerDone.load() >= nTotalWriters ) { + if ( m_Queue.empty() ) + break; + } + } + } + } + }; + + protected: + size_t m_nThreadPushCount; + + protected: + template + void analyze( Queue& q, size_t /*nLeftOffset*/ = 0, size_t nRightOffset = 0 ) + { + cds_test::thread_pool& pool = get_pool(); + + typedef Consumer Consumer; + typedef Producer Producer; + + size_t nPostTestPops = 0; + { + value_type v; + while ( q.pop( v )) + ++nPostTestPops; + } + + size_t nTotalPops = 0; + size_t nPopFalse = 0; + size_t nPoppedItems = 0; + size_t nPushFailed = 0; + + std::vector< Consumer * > arrConsumer; + + for ( size_t i = 0; i < pool.size(); ++i ) { + cds_test::thread& thr = pool.get(i); + if ( thr.type() == consumer_thread ) { + Consumer& consumer = static_cast( thr ); + nTotalPops += consumer.m_nPopped; + nPopFalse += consumer.m_nPopEmpty; + arrConsumer.push_back( &consumer ); + EXPECT_EQ( consumer.m_nBadWriter, 0 ) << "consumer_thread_no " << i; + + size_t nPopped = 0; + for ( size_t n = 0; n < s_nProducerThreadCount; ++n ) + nPopped += consumer.m_WriterData[n].size(); + + nPoppedItems += nPopped; + } + else { + assert( thr.type() == producer_thread ); + + Producer& producer = static_cast( thr ); + nPushFailed += producer.m_nPushFailed; + EXPECT_EQ( producer.m_nPushFailed, 0 ) << "producer_thread_no " << i; + } + } + EXPECT_EQ( nTotalPops, nPoppedItems ); + + EXPECT_EQ( nTotalPops + nPostTestPops, s_nQueueSize ) << "nTotalPops=" << nTotalPops << ", nPostTestPops=" << nPostTestPops; + EXPECT_TRUE( q.empty() ); + + // Test consistency of popped sequence + for ( size_t nWriter = 0; nWriter < s_nProducerThreadCount; ++nWriter ) { + std::vector arrData; + arrData.reserve( m_nThreadPushCount ); + for ( size_t nReader = 0; nReader < arrConsumer.size(); ++nReader ) { + auto it = arrConsumer[nReader]->m_WriterData[nWriter].begin(); + auto itEnd = arrConsumer[nReader]->m_WriterData[nWriter].end(); + if ( it != itEnd ) { + auto itPrev = it; + for ( ++it; it != itEnd; ++it ) { + EXPECT_LT( *itPrev, *it + nRightOffset ) << "consumer=" << nReader << ", producer=" << nWriter; + itPrev = it; + } + } + + for ( it = arrConsumer[nReader]->m_WriterData[nWriter].begin(); it != itEnd; ++it ) + arrData.push_back( *it ); + } + + std::sort( arrData.begin(), arrData.end() ); + for ( size_t i=1; i < arrData.size(); ++i ) { + EXPECT_EQ( arrData[i - 1] + 1, arrData[i] ) << "producer=" << nWriter; + } + + EXPECT_EQ( arrData[0], 0 ) << "producer=" << nWriter; + EXPECT_EQ( arrData[arrData.size() - 1], m_nThreadPushCount - 1 ) << "producer=" << nWriter; + } + } + + template + void test_queue( Queue& q ) + { + m_nThreadPushCount = s_nQueueSize / s_nProducerThreadCount; + + cds_test::thread_pool& pool = get_pool(); + pool.add( new Producer( pool, q, m_nThreadPushCount ), s_nProducerThreadCount ); + pool.add( new Consumer( pool, q, m_nThreadPushCount ), s_nConsumerThreadCount ); + + s_nProducerDone.store( 0 ); + s_nQueueSize = m_nThreadPushCount * s_nProducerThreadCount; + + propout() << std::make_pair( "producer_count", s_nProducerThreadCount ) + << std::make_pair( "consumer_count", s_nConsumerThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ); + + std::chrono::milliseconds duration = pool.run(); + + propout() << std::make_pair( "duration", duration ); + } + + template + void test( Queue& q ) + { + test_queue( q ); + analyze( q ); + propout() << q.statistics(); + } + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "queue_push_pop" ); + + s_nConsumerThreadCount = cfg.get_size_t( "ConsumerCount", s_nConsumerThreadCount ); + s_nProducerThreadCount = cfg.get_size_t( "ProducerCount", s_nProducerThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + + if ( s_nConsumerThreadCount == 0 ) + s_nConsumerThreadCount = 1; + if ( s_nProducerThreadCount == 0 ) + s_nProducerThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1000; + } + + //static void TearDownTestCase(); + }; + + CDSSTRESS_MSQueue( queue_push_pop ) + CDSSTRESS_MoirQueue( queue_push_pop ) + CDSSTRESS_BasketQueue( queue_push_pop ) + CDSSTRESS_OptimsticQueue( queue_push_pop ) + CDSSTRESS_FCQueue( queue_push_pop ) + CDSSTRESS_FCDeque( queue_push_pop ) + CDSSTRESS_RWQueue( queue_push_pop ) + CDSSTRESS_StdQueue( queue_push_pop ) + +#undef CDSSTRESS_Queue_F +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< value_type >::type_name queue_type; \ + queue_type queue( s_nQueueSize ); \ + test( queue ); \ + } + + CDSSTRESS_TsigasQueue( queue_push_pop ) + CDSSTRESS_VyukovQueue( queue_push_pop ) + +#undef CDSSTRESS_Queue_F + + + // ******************************************************************** + // SegmentedQueue test + + class segmented_queue_push_pop + : public queue_push_pop + , public ::testing::WithParamInterface< size_t > + { + typedef queue_push_pop base_class; + + protected: + + template + void test() + { + size_t quasi_factor = GetParam(); + + Queue q( quasi_factor ); + propout() << std::make_pair( "quasi_factor", quasi_factor ); + base_class::test_queue( q ); + analyze( q, quasi_factor * 2, quasi_factor ); + propout() << q.statistics(); + } + + public: + static std::vector< size_t > get_test_parameters() + { + cds_test::config const& cfg = cds_test::stress_fixture::get_config( "queue_push_pop" ); + bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false ); + size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 ); + + std::vector args; + if ( bIterative && quasi_factor > 4 ) { + for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 ) + args.push_back( qf ); + } + else { + if ( quasi_factor > 2 ) + args.push_back( quasi_factor ); + else + args.push_back( 2 ); + } + + return args; + } + }; + +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_P( test_fixture, type_name ) \ + { \ + typedef typename queue::Types::type_name queue_type; \ + test< queue_type >(); \ + } + + CDSSTRESS_SegmentedQueue( segmented_queue_push_pop ) + + INSTANTIATE_TEST_CASE_P( SQ, + segmented_queue_push_pop, + ::testing::ValuesIn( segmented_queue_push_pop::get_test_parameters())); + +} // namespace diff --git a/tests/unit/queue/queue_type.h b/test/stress/queue/queue_type.h similarity index 72% rename from tests/unit/queue/queue_type.h rename to test/stress/queue/queue_type.h index 337c609a..af76bc59 100644 --- a/tests/unit/queue/queue_type.h +++ b/test/stress/queue/queue_type.h @@ -28,8 +28,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CDSUNIT_QUEUE_TYPES_H -#define CDSUNIT_QUEUE_TYPES_H +#ifndef CDSSTRESS_QUEUE_TYPES_H +#define CDSSTRESS_QUEUE_TYPES_H #include #include @@ -45,14 +45,17 @@ #include #include -#include "queue/std_queue.h" +#include "std_queue.h" #include "lock/win32_lock.h" -#include "michael_alloc.h" -#include "print_segmentedqueue_stat.h" +#include "framework/michael_alloc.h" #include +#include +#include "print_stat.h" + namespace queue { + namespace details { template > class FCDequeL: public cds::container::FCDeque @@ -482,8 +485,8 @@ namespace queue { typedef StdQueue_deque StdQueue_deque_Spinlock; typedef StdQueue_list StdQueue_list_Spinlock; - typedef StdQueue_deque StdQueue_deque_BoostMutex; - typedef StdQueue_list StdQueue_list_BoostMutex; + typedef StdQueue_deque StdQueue_deque_Mutex; + typedef StdQueue_list StdQueue_list_Mutex; #ifdef UNIT_LOCK_WIN_CS typedef StdQueue_deque StdQueue_deque_WinCS; typedef StdQueue_list StdQueue_list_WinCS; @@ -539,136 +542,183 @@ namespace queue { // ********************************************* // Queue statistics -namespace std { +namespace cds_test { template - static inline std::ostream& operator <<(std::ostream& o, cds::container::basket_queue::stat const& s) + static inline property_stream& operator <<( property_stream& o, cds::container::fcqueue::stat const& s ) { - return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue empty: " << s.m_EmptyDequeue.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\t Advance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n" - << "\t\tAdd basket attempts: " << s.m_TryAddBasket.get() << "\n" - << "\t\t Add basket success: " << s.m_AddBasketCount.get() << "\n"; - } - static inline std::ostream& operator <<(std::ostream& o, cds::container::basket_queue::empty_stat const& /*s*/) - { - return o; + return o + << CDSSTRESS_STAT_OUT( s, m_nEnqueue ) + << CDSSTRESS_STAT_OUT( s, m_nEnqMove ) + << CDSSTRESS_STAT_OUT( s, m_nDequeue ) + << CDSSTRESS_STAT_OUT( s, m_nFailedDeq ) + << CDSSTRESS_STAT_OUT( s, m_nCollided ) + << CDSSTRESS_STAT_OUT_( "combining_factor", s.combining_factor() ) + << CDSSTRESS_STAT_OUT( s, m_nOperationCount ) + << CDSSTRESS_STAT_OUT( s, m_nCombiningCount ) + << CDSSTRESS_STAT_OUT( s, m_nCompactPublicationList ) + << CDSSTRESS_STAT_OUT( s, m_nDeactivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nActivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordCreated ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordDeteted ) + << CDSSTRESS_STAT_OUT( s, m_nAcquirePubRecCount ) + << CDSSTRESS_STAT_OUT( s, m_nReleasePubRecCount ); } - template - static inline std::ostream& operator <<( std::ostream& o, cds::container::msqueue::stat const& s ) - { - return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue empty: " << s.m_EmptyDequeue.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\tAdvance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n"; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::container::msqueue::empty_stat const& /*s*/ ) + static inline property_stream& operator <<( property_stream& o, cds::container::fcqueue::empty_stat const& /*s*/ ) { return o; } - static inline std::ostream& operator <<( std::ostream& o, cds::opt::none ) + static inline property_stream& operator <<( property_stream& o, cds::container::fcdeque::empty_stat const& /*s*/ ) { return o; } - // cds::intrusive::optimistic_queue::stat - template - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::optimistic_queue::stat const& s ) + static inline property_stream& operator <<( property_stream& o, cds::container::fcdeque::stat<> const& s ) { return o - << "\tStatistics:\n" - << "\t\t Enqueue count: " << s.m_EnqueueCount.get() << "\n" - << "\t\t Enqueue race: " << s.m_EnqueueRace.get() << "\n" - << "\t\t Dequeue count: " << s.m_DequeueCount.get() << "\n" - << "\t\t Dequeue empty: " << s.m_EmptyDequeue.get() << "\n" - << "\t\t Dequeue race: " << s.m_DequeueRace.get() << "\n" - << "\t\t Advance tail error: " << s.m_AdvanceTailError.get() << "\n" - << "\t\t Bad tail: " << s.m_BadTail.get() << "\n" - << "\t\t fix list call: " << s.m_FixListCount.get() << "\n"; - } - - static inline std::ostream& operator <<( std::ostream& o, cds::intrusive::optimistic_queue::empty_stat const& /*s*/ ) - { - return o; - } - - // cds::container::fcqueue::stat - template - static inline std::ostream& operator <<( std::ostream& o, cds::container::fcqueue::stat const& s ) - { - return o << "\tStatistics:\n" - << "\t Push: " << s.m_nEnqueue.get() << "\n" - << "\t PushMove: " << s.m_nEnqMove.get() << "\n" - << "\t Pop: " << s.m_nDequeue.get() << "\n" - << "\t FailedPop: " << s.m_nFailedDeq.get() << "\n" - << "\t Collided push/pop pair: " << s.m_nCollided.get() << "\n" - << "\tFlat combining statistics:\n" - << "\t Combining factor: " << s.combining_factor() << "\n" - << "\t Operation count: " << s.m_nOperationCount.get() << "\n" - << "\t Combine call count: " << s.m_nCombiningCount.get() << "\n" - << "\t Compact pub-list: " << s.m_nCompactPublicationList.get() << "\n" - << "\t Deactivate pub-record: " << s.m_nDeactivatePubRecord.get() << "\n" - << "\t Activate pub-record: " << s.m_nActivatePubRecord.get() << "\n" - << "\t Create pub-record: " << s.m_nPubRecordCreated.get() << "\n" - << "\t Delete pub-record: " << s.m_nPubRecordDeteted.get() << "\n" - << "\t Acquire pub-record: " << s.m_nAcquirePubRecCount.get()<< "\n" - << "\t Release pub-record: " << s.m_nReleasePubRecCount.get()<< "\n"; + << CDSSTRESS_STAT_OUT( s, m_nPushFront ) + << CDSSTRESS_STAT_OUT( s, m_nPushFrontMove ) + << CDSSTRESS_STAT_OUT( s, m_nPushBack ) + << CDSSTRESS_STAT_OUT( s, m_nPushBackMove ) + << CDSSTRESS_STAT_OUT( s, m_nPopFront ) + << CDSSTRESS_STAT_OUT( s, m_nFailedPopFront ) + << CDSSTRESS_STAT_OUT( s, m_nPopBack ) + << CDSSTRESS_STAT_OUT( s, m_nFailedPopBack ) + << CDSSTRESS_STAT_OUT( s, m_nCollided ) + << CDSSTRESS_STAT_OUT_( "combining_factor", s.combining_factor() ) + << CDSSTRESS_STAT_OUT( s, m_nOperationCount ) + << CDSSTRESS_STAT_OUT( s, m_nCombiningCount ) + << CDSSTRESS_STAT_OUT( s, m_nCompactPublicationList ) + << CDSSTRESS_STAT_OUT( s, m_nDeactivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nActivatePubRecord ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordCreated ) + << CDSSTRESS_STAT_OUT( s, m_nPubRecordDeteted ) + << CDSSTRESS_STAT_OUT( s, m_nAcquirePubRecCount ) + << CDSSTRESS_STAT_OUT( s, m_nReleasePubRecCount ); } - static inline std::ostream& operator <<( std::ostream& o, cds::container::fcqueue::empty_stat const& /*s*/ ) - { - return o; - } +} // namespace cds_test - static inline std::ostream& operator <<( std::ostream& o, std::nullptr_t /*s*/ ) - { - return o; +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< value_type >::type_name queue_type; \ + queue_type queue; \ + test( queue ); \ } - static inline ostream& operator <<( ostream& o, cds::container::fcdeque::empty_stat const& /*s*/ ) - { - return o; - } - - static inline ostream& operator <<( ostream& o, cds::container::fcdeque::stat<> const& s ) - { - return o << "\tStatistics:\n" - << "\t Push front: " << s.m_nPushFront.get() << "\n" - << "\t Push front move: " << s.m_nPushFrontMove.get() << "\n" - << "\t Push back: " << s.m_nPushBack.get() << "\n" - << "\t Push back move: " << s.m_nPushBackMove.get() << "\n" - << "\t Pop front: " << s.m_nPopFront.get() << "\n" - << "\t Failed pop front: " << s.m_nFailedPopFront.get() << "\n" - << "\t Pop back: " << s.m_nPopBack.get() << "\n" - << "\t Failed pop back: " << s.m_nFailedPopBack.get() << "\n" - << "\t Collided push/pop pair: " << s.m_nCollided.get() << "\n" - << "\tFlat combining statistics:\n" - << "\t Combining factor: " << s.combining_factor() << "\n" - << "\t Operation count: " << s.m_nOperationCount.get() << "\n" - << "\t Combine call count: " << s.m_nCombiningCount.get() << "\n" - << "\t Compact pub-list: " << s.m_nCompactPublicationList.get() << "\n" - << "\t Deactivate pub-record: " << s.m_nDeactivatePubRecord.get() << "\n" - << "\t Activate pub-record: " << s.m_nActivatePubRecord.get() << "\n" - << "\t Create pub-record: " << s.m_nPubRecordCreated.get() << "\n" - << "\t Delete pub-record: " << s.m_nPubRecordDeteted.get() << "\n" - << "\t Acquire pub-record: " << s.m_nAcquirePubRecCount.get()<< "\n" - << "\t Release pub-record: " << s.m_nReleasePubRecCount.get()<< "\n"; - } - -} - -#endif // #ifndef CDSUNIT_QUEUE_TYPES_H +#define CDSSTRESS_MSQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_HP ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_HP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_HP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_HP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_HP_stat ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_DHP ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_DHP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_DHP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_DHP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, MSQueue_DHP_stat ) + +#define CDSSTRESS_MoirQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_HP ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_HP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_HP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_HP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_HP_stat ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_DHP ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_DHP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_DHP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_DHP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, MoirQueue_DHP_stat ) + +#define CDSSTRESS_OptimsticQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_HP ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_HP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_HP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_HP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_HP_stat ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_DHP ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_DHP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_DHP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_DHP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, OptimisticQueue_DHP_stat ) + +#define CDSSTRESS_BasketQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_HP ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_HP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_HP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_HP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_HP_stat ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_DHP ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_DHP_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_DHP_seqcst ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_DHP_ic ) \ + CDSSTRESS_Queue_F( test_fixture, BasketQueue_DHP_stat ) + +#define CDSSTRESS_FCQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_deque ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_deque_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_deque_elimination_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_list ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_list_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCQueue_list_elimination_stat ) + +#define CDSSTRESS_FCDeque( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_default ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_mutex ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_elimination_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_boost ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_boost_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_boost_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeL_boost_elimination_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_default ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_mutex ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_elimination_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_boost ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_boost_stat ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_boost_elimination ) \ + CDSSTRESS_Queue_F( test_fixture, FCDequeR_boost_elimination_stat ) + +#define CDSSTRESS_RWQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, RWQueue_Spin ) \ + CDSSTRESS_Queue_F( test_fixture, RWQueue_Spin_ic ) \ + CDSSTRESS_Queue_F( test_fixture, RWQueue_mutex ) + +#define CDSSTRESS_SegmentedQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_spin ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_spin_padding ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_spin_stat ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_mutex ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_mutex_padding ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_HP_mutex_stat ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_spin ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_spin_padding ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_spin_stat ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_mutex ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_mutex_padding ) \ + CDSSTRESS_Queue_F( test_fixture, SegmentedQueue_DHP_mutex_stat ) + + +#define CDSSTRESS_TsigasQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, TsigasCycleQueue_dyn ) \ + CDSSTRESS_Queue_F( test_fixture, TsigasCycleQueue_dyn_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, TsigasCycleQueue_dyn_ic ) + +#define CDSSTRESS_VyukovQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, VyukovMPMCCycleQueue_dyn ) \ + CDSSTRESS_Queue_F( test_fixture, VyukovMPMCCycleQueue_dyn_michaelAlloc ) \ + CDSSTRESS_Queue_F( test_fixture, VyukovMPMCCycleQueue_dyn_ic ) + +#define CDSSTRESS_StdQueue( test_fixture ) \ + CDSSTRESS_Queue_F( test_fixture, StdQueue_deque_Spinlock ) \ + CDSSTRESS_Queue_F( test_fixture, StdQueue_list_Spinlock ) \ + CDSSTRESS_Queue_F( test_fixture, StdQueue_deque_Mutex ) \ + CDSSTRESS_Queue_F( test_fixture, StdQueue_list_Mutex ) + +#endif // #ifndef CDSSTRESS_QUEUE_TYPES_H diff --git a/test/stress/queue/random.cpp b/test/stress/queue/random.cpp new file mode 100644 index 00000000..65b81a26 --- /dev/null +++ b/test/stress/queue/random.cpp @@ -0,0 +1,330 @@ +/* + This file is a part of libcds - Concurrent Data Structures library + + (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 + + Source code repo: http://github.com/khizmax/libcds/ + Download: http://sourceforge.net/projects/libcds/files/ + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "queue_type.h" + +#include + +// Multi-threaded queue test for random push/pop operation +namespace { + + static size_t s_nThreadCount = 16; + static size_t s_nQueueSize = 10000000; + + std::atomic< size_t > s_nProducerCount(0); + + class queue_random: public cds_test::stress_fixture + { + typedef cds_test::stress_fixture base_class; + + protected: + struct value_type { + size_t nNo; + size_t nThread; + + value_type() {} + value_type( size_t n ) : nNo( n ) {} + }; + + template + class Strain: public cds_test::thread + { + typedef cds_test::thread base_class; + + public: + Strain( cds_test::thread_pool& pool, Queue& q, size_t nPushCount, size_t nSpread = 0 ) + : base_class( pool ) + , m_Queue( q ) + , m_nSpread( nSpread ) + , m_nTotalPushCount( nPushCount ) + {} + + Strain( Strain& src ) + : base_class( src ) + , m_Queue( src.m_Queue ) + , m_nSpread( src.m_nSpread ) + , m_nTotalPushCount( src.m_nTotalPushCount ) + {} + + virtual thread * clone() + { + return new Strain( *this ); + } + + virtual void test() + { + size_t const nThreadCount = s_nThreadCount; + size_t const nTotalPush = m_nTotalPushCount; + + m_arrLastRead.resize( nThreadCount, 0 ); + m_arrPopCountPerThread.resize( nThreadCount, 0 ); + + value_type node; + + while ( m_nPushCount < nTotalPush ) { + if ( (rand() & 3) != 3 ) { + node.nThread = id(); + node.nNo = ++m_nPushCount; + if ( !m_Queue.push( node )) { + ++m_nPushError; + --m_nPushCount; + } + } + else + pop( nThreadCount ); + } + + s_nProducerCount.fetch_sub( 1, std::memory_order_relaxed ); + + while ( !m_Queue.empty() || s_nProducerCount.load( std::memory_order_relaxed ) != 0 ) + pop( nThreadCount ); + } + + bool pop( size_t nThreadCount ) + { + value_type node; + node.nThread = nThreadCount; + node.nNo = ~0; + if ( m_Queue.pop( node )) { + ++m_nPopCount; + if ( node.nThread < nThreadCount ) { + m_arrPopCountPerThread[ node.nThread ] += 1; + if ( m_nSpread ) { + if ( m_arrLastRead[ node.nThread ] > node.nNo ) { + if ( m_arrLastRead[ node.nThread ] - node.nNo > m_nSpread ) + ++m_nRepeatValue; + } + else if ( m_arrLastRead[ node.nThread ] == node.nNo ) + ++m_nRepeatValue; + m_arrLastRead[ node.nThread ] = node.nNo; + } + else { + if ( m_arrLastRead[ node.nThread ] < node.nNo ) + m_arrLastRead[ node.nThread ] = node.nNo; + else + ++m_nRepeatValue; + } + } + else + ++m_nUndefWriter; + } + else { + ++m_nEmptyPop; + return false; + } + return true; + } + + public: + Queue& m_Queue; + + size_t m_nPushCount = 0; + size_t m_nPopCount = 0; + size_t m_nEmptyPop = 0; + + size_t m_nUndefWriter = 0; + size_t m_nRepeatValue = 0; + size_t m_nPushError = 0; + + std::vector m_arrLastRead; + std::vector m_arrPopCountPerThread; + + size_t const m_nSpread; + size_t const m_nTotalPushCount; + }; + + public: + static void SetUpTestCase() + { + cds_test::config const& cfg = get_config( "queue_random" ); + + s_nThreadCount = cfg.get_size_t( "ThreadCount", s_nThreadCount ); + s_nQueueSize = cfg.get_size_t( "QueueSize", s_nQueueSize ); + + if ( s_nThreadCount == 0 ) + s_nThreadCount = 1; + if ( s_nQueueSize == 0 ) + s_nQueueSize = 1000; + } + + //static void TearDownTestCase(); + + protected: + template + void analyze( Queue& q ) + { + EXPECT_TRUE( q.empty() ); + + std::vector< size_t > arrPushCount; + arrPushCount.resize( s_nThreadCount, 0 ); + + size_t nPushTotal = 0; + size_t nPopTotal = 0; + size_t nPushError = 0; + + cds_test::thread_pool& pool = get_pool(); + for ( size_t i = 0; i < pool.size(); ++i ) { + Strain& thr = static_cast &>( pool.get(i)); + EXPECT_EQ( thr.m_nUndefWriter, 0 ); + EXPECT_EQ( thr.m_nRepeatValue, 0 ); + EXPECT_EQ( thr.m_nPushError, 0 ); + nPushError += thr.m_nPushError; + + arrPushCount[ thr.id() ] += thr.m_nPushCount; + + nPushTotal += thr.m_nPushCount; + nPopTotal += thr.m_nPopCount; + } + + EXPECT_EQ( nPushTotal, s_nQueueSize ); + EXPECT_EQ( nPopTotal, s_nQueueSize ); + + size_t const nThreadPushCount = s_nQueueSize / s_nThreadCount; + for ( size_t i = 0; i < s_nThreadCount; ++i ) + EXPECT_EQ( arrPushCount[i], nThreadPushCount ) << "thread=" << i; + } + + template + void test( Queue& q ) + { + size_t nThreadPushCount = s_nQueueSize / s_nThreadCount; + + cds_test::thread_pool& pool = get_pool(); + pool.add( new Strain( pool, q, nThreadPushCount ), s_nThreadCount ); + + s_nQueueSize = nThreadPushCount * s_nThreadCount; + propout() << std::make_pair( "thread_count", s_nThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ); + + s_nProducerCount.store( pool.size(), std::memory_order_release ); + std::chrono::milliseconds duration = pool.run(); + propout() << std::make_pair( "duration", duration ); + + analyze( q ); + + propout() << q.statistics(); + } + }; + + CDSSTRESS_MSQueue( queue_random ) + CDSSTRESS_MoirQueue( queue_random ) + CDSSTRESS_BasketQueue( queue_random ) + CDSSTRESS_OptimsticQueue( queue_random ) + CDSSTRESS_FCQueue( queue_random ) + CDSSTRESS_FCDeque( queue_random ) + CDSSTRESS_RWQueue( queue_random ) + CDSSTRESS_StdQueue( queue_random ) + +#undef CDSSTRESS_Queue_F +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_F( test_fixture, type_name ) \ + { \ + typedef queue::Types< value_type >::type_name queue_type; \ + queue_type queue( s_nQueueSize ); \ + test( queue ); \ + } + + CDSSTRESS_TsigasQueue( queue_random ) + CDSSTRESS_VyukovQueue( queue_random ) + +#undef CDSSTRESS_Queue_F + + // ******************************************************************** + // SegmentedQueue test + + class segmented_queue_random + : public queue_random + , public ::testing::WithParamInterface< size_t > + { + typedef queue_random base_class; + + protected: + template + void test() + { + size_t quasi_factor = GetParam(); + + Queue q( quasi_factor ); + propout() << std::make_pair( "quasi_factor", quasi_factor ); + + size_t nThreadPushCount = s_nQueueSize / s_nThreadCount; + + cds_test::thread_pool& pool = get_pool(); + pool.add( new Strain( pool, q, nThreadPushCount, quasi_factor * 2 ), s_nThreadCount ); + + s_nQueueSize = nThreadPushCount * s_nThreadCount; + propout() << std::make_pair( "thread_count", s_nThreadCount ) + << std::make_pair( "push_count", s_nQueueSize ); + + s_nProducerCount.store( pool.size(), std::memory_order_release ); + std::chrono::milliseconds duration = pool.run(); + propout() << std::make_pair( "duration", duration ); + + analyze( q ); + + propout() << q.statistics(); + } + + public: + static std::vector< size_t > get_test_parameters() + { + cds_test::config const& cfg = cds_test::stress_fixture::get_config( "queue_push" ); + bool bIterative = cfg.get_bool( "SegmentedQueue_Iterate", false ); + size_t quasi_factor = cfg.get_size_t( "SegmentedQueue_SegmentSize", 256 ); + + std::vector args; + if ( bIterative && quasi_factor > 4 ) { + for ( size_t qf = 4; qf <= quasi_factor; qf *= 2 ) + args.push_back( qf ); + } + else { + if ( quasi_factor > 2 ) + args.push_back( quasi_factor ); + else + args.push_back( 2 ); + } + + return args; + } + }; + +#define CDSSTRESS_Queue_F( test_fixture, type_name ) \ + TEST_P( test_fixture, type_name ) \ + { \ + typedef typename queue::Types::type_name queue_type; \ + test< queue_type >(); \ + } + + CDSSTRESS_SegmentedQueue( segmented_queue_random ) + + INSTANTIATE_TEST_CASE_P( SQ, + segmented_queue_random, + ::testing::ValuesIn( segmented_queue_random::get_test_parameters())); +} // namespace diff --git a/tests/unit/queue/std_queue.h b/test/stress/queue/std_queue.h similarity index 95% rename from tests/unit/queue/std_queue.h rename to test/stress/queue/std_queue.h index d24916c8..b8276aab 100644 --- a/tests/unit/queue/std_queue.h +++ b/test/stress/queue/std_queue.h @@ -33,6 +33,7 @@ #include //unique_lock #include +#include #include namespace queue { @@ -71,12 +72,10 @@ namespace queue { }; template - class StdQueue_deque: public StdQueue, Lock > - {}; + using StdQueue_deque = StdQueue, Lock >; template - class StdQueue_list: public StdQueue, Lock > - {}; + using StdQueue_list = StdQueue, Lock >; } #endif // #ifndef CDSUNIT_QUEUE_STD_QUEUE_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3de95852..2b16f072 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,5 +13,5 @@ add_library(${TEST_COMMON} OBJECT ${SOURCES}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/test-hdr) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/unit) -file(GLOB CONF_FILES ${PROJECT_SOURCE_DIR}/tests/data/*.conf) -file(COPY ${CONF_FILES} DESTINATION ${EXECUTABLE_OUTPUT_PATH}) \ No newline at end of file +#file(GLOB CONF_FILES ${PROJECT_SOURCE_DIR}/tests/data/*.conf) +#file(COPY ${CONF_FILES} DESTINATION ${EXECUTABLE_OUTPUT_PATH}) \ No newline at end of file diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 8ba101ad..fcf80bb2 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -16,5 +16,4 @@ add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUT add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/map2) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/pqueue) -add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/queue) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/set2) diff --git a/tests/unit/queue/CMakeLists.txt b/tests/unit/queue/CMakeLists.txt deleted file mode 100644 index f41f29cf..00000000 --- a/tests/unit/queue/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(PACKAGE_NAME cdsu-queue) - -set(CDSUNIT_QUEUE_SOURCES - bounded_queue_fulness.cpp - queue_pop.cpp - queue_push.cpp - queue_random.cpp - queue_reader_writer.cpp - intrusive_queue_reader_writer.cpp) - -add_executable(${PACKAGE_NAME} ${CDSUNIT_QUEUE_SOURCES} $) -target_link_libraries(${PACKAGE_NAME} ${CDS_SHARED_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) -add_test(NAME ${PACKAGE_NAME} COMMAND ${PACKAGE_NAME} WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) \ No newline at end of file diff --git a/tests/unit/queue/bounded_queue_fulness.cpp b/tests/unit/queue/bounded_queue_fulness.cpp deleted file mode 100644 index 61bce409..00000000 --- a/tests/unit/queue/bounded_queue_fulness.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/queue_type.h" -#include "queue/queue_defs.h" - - -/* - Bounded queue test. - The test checks the behaviour of bounded queue when it is almost full. - Many algorithms says the queue is full when it is not, and vice versa. -*/ -namespace queue { - -#define TEST_BOUNDED( Q, V ) void Q() { test< Types::Q >(); } - - namespace ns_BoundedQueue_Fullness { - static size_t s_nThreadCount = 8; - static size_t s_nQueueSize = 1024; - static size_t s_nPassCount = 1000000; - } - using namespace ns_BoundedQueue_Fullness; - - class BoundedQueue_Fullness: public CppUnitMini::TestCase - { - template - class Thread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Thread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nPushError; - size_t m_nPopError; - - public: - Thread( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - {} - Thread( Thread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - {} - - BoundedQueue_Fullness& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_fTime = m_Timer.duration(); - - m_nPushError = 0; - m_nPopError = 0; - for ( size_t i = 0; i < s_nPassCount; ++i ) { - if ( !m_Queue.push( i )) - ++m_nPushError; - size_t item; - if ( !m_Queue.pop( item )) - ++m_nPopError; - } - m_fTime = m_Timer.duration() - m_fTime; - } - }; - - protected: - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue ) - { - double fTime = 0; - size_t nPushError = 0; - size_t nPopError = 0; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - fTime += pThread->m_fTime; - nPushError += pThread->m_nPushError; - nPopError += pThread->m_nPopError; - } - CPPUNIT_MSG( " Duration=" << (fTime / s_nThreadCount) ); - CPPUNIT_MSG( " Errors: push=" << nPushError << ", pop=" << nPopError ); - CPPUNIT_CHECK( !testQueue.empty()); - CPPUNIT_CHECK( nPushError == 0 ); - CPPUNIT_CHECK( nPopError == 0 ); - } - - template - void test() - { - Queue testQueue( s_nQueueSize ); - - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - size_t nSize = testQueue.capacity() - s_nThreadCount; - for ( size_t i = 0; i < nSize; ++i ) - testQueue.push( i ); - - CPPUNIT_MSG( " Thread count=" << s_nThreadCount << ", push/pop pairs=" << s_nPassCount - - << ", queue capacity=" << testQueue.capacity() << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nThreadCount = cfg.getULong("ThreadCount", 8 ); - s_nQueueSize = cfg.getULong("QueueSize", 1024 ); - s_nPassCount = cfg.getULong( "PassCount", 1000000 ); - } - - protected: - CDSUNIT_DECLARE_TsigasCycleQueue( size_t ) - CDSUNIT_DECLARE_VyukovMPMCCycleQueue( size_t ) - - CPPUNIT_TEST_SUITE( BoundedQueue_Fullness ) - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::BoundedQueue_Fullness ); diff --git a/tests/unit/queue/intrusive_queue_defs.h b/tests/unit/queue/intrusive_queue_defs.h deleted file mode 100644 index 4a5dca64..00000000 --- a/tests/unit/queue/intrusive_queue_defs.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef CDSUNIT_INTRUSIVE_QUEUE_DEFS_H -#define CDSUNIT_INTRUSIVE_QUEUE_DEFS_H - -// MSQueue -#define CDSUNIT_DECLARE_MSQueue \ - TEST_CASE(MSQueue_HP, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MSQueue_HP_ic, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MSQueue_HP_stat, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MSQueue_HP_seqcst, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MSQueue_DHP, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MSQueue_DHP_ic, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MSQueue_DHP_stat, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MSQueue_DHP_seqcst, cds::intrusive::msqueue::node< cds::gc::DHP > ) - -#define CDSUNIT_TEST_MSQueue \ - CPPUNIT_TEST(MSQueue_HP) \ - CPPUNIT_TEST(MSQueue_HP_ic) \ - CPPUNIT_TEST(MSQueue_HP_stat) \ - CPPUNIT_TEST(MSQueue_HP_seqcst) \ - CPPUNIT_TEST(MSQueue_DHP) \ - CPPUNIT_TEST(MSQueue_DHP_ic) \ - CPPUNIT_TEST(MSQueue_DHP_stat) \ - CPPUNIT_TEST(MSQueue_DHP_seqcst) - -// MoirQueue -#define CDSUNIT_DECLARE_MoirQueue \ - TEST_CASE(MoirQueue_HP, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MoirQueue_HP_ic, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MoirQueue_HP_stat, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MoirQueue_HP_seqcst, cds::intrusive::msqueue::node< cds::gc::HP > ) \ - TEST_CASE(MoirQueue_DHP, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MoirQueue_DHP_ic, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MoirQueue_DHP_stat, cds::intrusive::msqueue::node< cds::gc::DHP > ) \ - TEST_CASE(MoirQueue_DHP_seqcst, cds::intrusive::msqueue::node< cds::gc::DHP > ) - -#define CDSUNIT_TEST_MoirQueue \ - CPPUNIT_TEST(MoirQueue_HP) \ - CPPUNIT_TEST(MoirQueue_HP_ic) \ - CPPUNIT_TEST(MoirQueue_HP_stat) \ - CPPUNIT_TEST(MoirQueue_HP_seqcst) \ - CPPUNIT_TEST(MoirQueue_DHP) \ - CPPUNIT_TEST(MoirQueue_DHP_ic) \ - CPPUNIT_TEST(MoirQueue_DHP_stat) \ - CPPUNIT_TEST(MoirQueue_DHP_seqcst) - - -// OptimisticQueue -#define CDSUNIT_DECLARE_OptimisticQueue \ - TEST_CASE(OptimisticQueue_HP, cds::intrusive::optimistic_queue::node< cds::gc::HP > ) \ - TEST_CASE(OptimisticQueue_HP_ic, cds::intrusive::optimistic_queue::node< cds::gc::HP > ) \ - TEST_CASE(OptimisticQueue_HP_stat, cds::intrusive::optimistic_queue::node< cds::gc::HP > ) \ - TEST_CASE(OptimisticQueue_HP_seqcst, cds::intrusive::optimistic_queue::node< cds::gc::HP > ) \ - TEST_CASE(OptimisticQueue_DHP, cds::intrusive::optimistic_queue::node< cds::gc::DHP > ) \ - TEST_CASE(OptimisticQueue_DHP_ic, cds::intrusive::optimistic_queue::node< cds::gc::DHP > ) \ - TEST_CASE(OptimisticQueue_DHP_stat, cds::intrusive::optimistic_queue::node< cds::gc::DHP > ) \ - TEST_CASE(OptimisticQueue_DHP_seqcst, cds::intrusive::optimistic_queue::node< cds::gc::DHP > ) - -#define CDSUNIT_TEST_OptimisticQueue \ - CPPUNIT_TEST(OptimisticQueue_HP) \ - CPPUNIT_TEST(OptimisticQueue_HP_ic) \ - CPPUNIT_TEST(OptimisticQueue_HP_stat) \ - CPPUNIT_TEST(OptimisticQueue_HP_seqcst) \ - CPPUNIT_TEST(OptimisticQueue_DHP) \ - CPPUNIT_TEST(OptimisticQueue_DHP_ic) \ - CPPUNIT_TEST(OptimisticQueue_DHP_stat) \ - CPPUNIT_TEST(OptimisticQueue_DHP_seqcst) - - -// BasketQueue -#define CDSUNIT_DECLARE_BasketQueue \ - TEST_CASE(BasketQueue_HP, cds::intrusive::basket_queue::node< cds::gc::HP > ) \ - TEST_CASE(BasketQueue_HP_ic, cds::intrusive::basket_queue::node< cds::gc::HP > ) \ - TEST_CASE(BasketQueue_HP_stat, cds::intrusive::basket_queue::node< cds::gc::HP > ) \ - TEST_CASE(BasketQueue_HP_seqcst, cds::intrusive::basket_queue::node< cds::gc::HP > ) \ - TEST_CASE(BasketQueue_DHP, cds::intrusive::basket_queue::node< cds::gc::DHP > ) \ - TEST_CASE(BasketQueue_DHP_ic, cds::intrusive::basket_queue::node< cds::gc::DHP > ) \ - TEST_CASE(BasketQueue_DHP_stat, cds::intrusive::basket_queue::node< cds::gc::DHP > ) \ - TEST_CASE(BasketQueue_DHP_seqcst, cds::intrusive::basket_queue::node< cds::gc::DHP > ) - -#define CDSUNIT_TEST_BasketQueue \ - CPPUNIT_TEST(BasketQueue_HP) \ - CPPUNIT_TEST(BasketQueue_HP_ic) \ - CPPUNIT_TEST(BasketQueue_HP_stat) \ - CPPUNIT_TEST(BasketQueue_HP_seqcst) \ - CPPUNIT_TEST(BasketQueue_DHP) \ - CPPUNIT_TEST(BasketQueue_DHP_ic) \ - CPPUNIT_TEST(BasketQueue_DHP_stat) \ - CPPUNIT_TEST(BasketQueue_DHP_seqcst) - -// TsigasCycleQueue -#define CDSUNIT_DECLARE_TsigasCycleQueue \ - TEST_BOUNDED(TsigasCycleQueue_dyn) \ - TEST_BOUNDED(TsigasCycleQueue_dyn_ic) - -#define CDSUNIT_TEST_TsigasCycleQueue \ - CPPUNIT_TEST(TsigasCycleQueue_dyn) \ - CPPUNIT_TEST(TsigasCycleQueue_dyn_ic) - - -// VyukovMPMCCycleQueue -#define CDSUNIT_DECLARE_VyukovMPMCCycleQueue \ - TEST_BOUNDED(VyukovMPMCCycleQueue_dyn) \ - TEST_BOUNDED(VyukovMPMCCycleQueue_dyn_ic) - -#define CDSUNIT_TEST_VyukovMPMCCycleQueue \ - CPPUNIT_TEST(VyukovMPMCCycleQueue_dyn) \ - CPPUNIT_TEST(VyukovMPMCCycleQueue_dyn_ic) - - -// FCQueue -#define CDSUNIT_DECLARE_FCQueue \ - TEST_FCQUEUE(FCQueue_list_delay2, boost::intrusive::list_base_hook<> ) \ - TEST_FCQUEUE(FCQueue_list_delay2_elimination, boost::intrusive::list_base_hook<> ) \ - TEST_FCQUEUE(FCQueue_list_delay2_elimination_stat, boost::intrusive::list_base_hook<> ) \ - TEST_FCQUEUE(FCQueue_list_expbackoff_elimination, boost::intrusive::list_base_hook<> ) \ - TEST_FCQUEUE(FCQueue_list_expbackoff_elimination_stat, boost::intrusive::list_base_hook<> ) - -#define CDSUNIT_TEST_FCQueue \ - CPPUNIT_TEST(FCQueue_list_delay2) \ - CPPUNIT_TEST(FCQueue_list_delay2_elimination) \ - CPPUNIT_TEST(FCQueue_list_delay2_elimination_stat) \ - CPPUNIT_TEST(FCQueue_list_expbackoff_elimination) \ - CPPUNIT_TEST(FCQueue_list_expbackoff_elimination_stat) - -// SegmentedQueue -#define CDSUNIT_DECLARE_SegmentedQueue \ - TEST_SEGMENTED( SegmentedQueue_HP_spin ) \ - TEST_SEGMENTED( SegmentedQueue_HP_spin_padding ) \ - TEST_SEGMENTED( SegmentedQueue_HP_spin_stat ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex_padding ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex_stat ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin_padding ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin_stat ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex_padding ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex_stat ) - -#define CDSUNIT_TEST_SegmentedQueue \ - CPPUNIT_TEST( SegmentedQueue_HP_spin ) \ - CPPUNIT_TEST( SegmentedQueue_HP_spin_padding ) \ - CPPUNIT_TEST( SegmentedQueue_HP_spin_stat ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex_padding ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex_stat ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin_padding ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin_stat ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex_padding ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex_stat ) - - -// BoostSList -#define CDSUNIT_DECLARE_BoostSList \ - TEST_BOOST( BoostSList_mutex, boost::intrusive::slist_base_hook<> ) \ - TEST_BOOST( BoostSList_spin, boost::intrusive::slist_base_hook<> ) - -#define CDSUNIT_TEST_BoostSList \ - CPPUNIT_TEST( BoostSList_mutex ) \ - CPPUNIT_TEST( BoostSList_spin ) - -#endif // #ifndef CDSUNIT_INTRUSIVE_QUEUE_DEFS_H diff --git a/tests/unit/queue/intrusive_queue_reader_writer.cpp b/tests/unit/queue/intrusive_queue_reader_writer.cpp deleted file mode 100644 index fb9217c9..00000000 --- a/tests/unit/queue/intrusive_queue_reader_writer.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/intrusive_queue_type.h" -#include "queue/intrusive_queue_defs.h" -#include -#include - -// Multi-threaded random queue test -namespace queue { - -#define TEST_CASE( Q, HOOK ) void Q() { test< Types< Value >::Q >(); } -#define TEST_BOUNDED( Q ) void Q() { test_bounded< Types< Value<> >::Q >(); } -#define TEST_FCQUEUE( Q, HOOK ) void Q() { test_fcqueue< Types< Value >::Q >(); } -#define TEST_SEGMENTED( Q ) void Q() { test_segmented< Types< Value<> >::Q >(); } -#define TEST_BOOST( Q, HOOK ) void Q() { test_boost< Types< Value >::Q >(); } - - namespace { - static size_t s_nReaderThreadCount = 4; - static size_t s_nWriterThreadCount = 4; - static size_t s_nQueueSize = 4000000; - static unsigned int s_nFCPassCount = 8; - static unsigned int s_nFCCompactFactor = 64; - - struct empty {}; - - template - struct Value: public Base - { - size_t nNo; - size_t nWriterNo; - size_t nConsumer; - }; - } - - class IntrusiveQueue_ReaderWriter: public CppUnitMini::TestCase - { - template - class Producer: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Producer( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nPushFailed; - - // Interval in m_arrValue - typename Queue::value_type * m_pStart; - typename Queue::value_type * m_pEnd; - - public: - Producer( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - {} - Producer( Producer& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - {} - - IntrusiveQueue_ReaderWriter& getTest() - { - return static_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_nPushFailed = 0; - - m_fTime = m_Timer.duration(); - - size_t i = 0; - for ( typename Queue::value_type * p = m_pStart; p < m_pEnd; ) { - p->nNo = i; - p->nWriterNo = m_nThreadNo; - CDS_TSAN_ANNOTATE_HAPPENS_BEFORE( &p->nWriterNo ); - if ( m_Queue.push( *p )) { - ++p; - ++i; - } - else - ++m_nPushFailed; - } - - m_fTime = m_Timer.duration() - m_fTime; - getTest().m_nProducerCount.fetch_sub( 1, atomics::memory_order_release ); - } - }; - - template - class Consumer: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Consumer( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nPopEmpty; - size_t m_nPopped; - size_t m_nBadWriter; - - typedef std::vector TPoppedData; - typedef std::vector::iterator data_iterator; - typedef std::vector::const_iterator const_data_iterator; - - std::vector m_WriterData; - - private: - void initPoppedData() - { - const size_t nWriterCount = s_nWriterThreadCount; - const size_t nWriterPushCount = getTest().m_nThreadPushCount; - m_WriterData.resize( nWriterCount ); - for ( size_t i = 0; i < nWriterCount; ++i ) - m_WriterData[i].reserve( nWriterPushCount ); - } - - public: - Consumer( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - { - initPoppedData(); - } - Consumer( Consumer& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - { - initPoppedData(); - } - - IntrusiveQueue_ReaderWriter& getTest() - { - return static_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_nPopEmpty = 0; - m_nPopped = 0; - m_nBadWriter = 0; - const size_t nTotalWriters = s_nWriterThreadCount; - - m_fTime = m_Timer.duration(); - - while ( true ) { - typename Queue::value_type * p = m_Queue.pop(); - if ( p ) { - p->nConsumer = m_nThreadNo; - ++m_nPopped; - CDS_TSAN_ANNOTATE_HAPPENS_AFTER( &p->nWriterNo ); - if ( p->nWriterNo < nTotalWriters ) - m_WriterData[ p->nWriterNo ].push_back( p->nNo ); - else - ++m_nBadWriter; - } - else { - ++m_nPopEmpty; - if ( getTest().m_nProducerCount.load( atomics::memory_order_acquire ) == 0 && m_Queue.empty() ) - break; - } - } - - m_fTime = m_Timer.duration() - m_fTime; - } - }; - - template - class value_array - { - T * m_pArr; - public: - value_array( size_t nSize ) - : m_pArr( new T[nSize] ) - {} - - ~value_array() - { - delete [] m_pArr; - } - - T * get() const { return m_pArr; } - }; - - - protected: - size_t m_nThreadPushCount; - atomics::atomic m_nProducerCount; - static CDS_CONSTEXPR const size_t c_nBadConsumer = 0xbadc0ffe; - - protected: - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue, size_t /*nLeftOffset*/, size_t nRightOffset ) - { - typedef Consumer Reader; - typedef Producer Writer; - typedef typename Reader::const_data_iterator ReaderIterator; - - size_t nPostTestPops = 0; - while ( testQueue.pop() ) - ++nPostTestPops; - - double fTimeWriter = 0; - double fTimeReader = 0; - size_t nTotalPops = 0; - size_t nPopFalse = 0; - size_t nPoppedItems = 0; - size_t nPushFailed = 0; - - std::vector< Reader * > arrReaders; - - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Reader * pReader = dynamic_cast( *it ); - if ( pReader ) { - fTimeReader += pReader->m_fTime; - nTotalPops += pReader->m_nPopped; - nPopFalse += pReader->m_nPopEmpty; - arrReaders.push_back( pReader ); - CPPUNIT_CHECK_EX( pReader->m_nBadWriter == 0, "reader " << pReader->m_nThreadNo << " bad writer event count=" << pReader->m_nBadWriter ); - - size_t nPopped = 0; - for ( size_t n = 0; n < s_nWriterThreadCount; ++n ) - nPopped += pReader->m_WriterData[n].size(); - - CPPUNIT_MSG( " Reader " << pReader->m_nThreadNo - s_nWriterThreadCount << " popped count=" << nPopped ); - nPoppedItems += nPopped; - } - else { - Writer * pWriter = dynamic_cast( *it ); - CPPUNIT_ASSERT( pWriter != nullptr ); - fTimeWriter += pWriter->m_fTime; - nPushFailed += pWriter->m_nPushFailed; - if ( !boost::is_base_of::value ) { - CPPUNIT_CHECK_EX( pWriter->m_nPushFailed == 0, - "writer " << pWriter->m_nThreadNo << " push failed count=" << pWriter->m_nPushFailed ); - } - } - } - CPPUNIT_CHECK_EX( nTotalPops == nPoppedItems, "nTotalPops=" << nTotalPops << ", nPoppedItems=" << nPoppedItems ); - - CPPUNIT_MSG( " Readers: duration=" << fTimeReader / s_nReaderThreadCount << ", success pop=" << nTotalPops << ", failed pops=" << nPopFalse ); - CPPUNIT_MSG( " Writers: duration=" << fTimeWriter / s_nWriterThreadCount << ", failed push=" << nPushFailed ); - - size_t nQueueSize = m_nThreadPushCount * s_nWriterThreadCount; - CPPUNIT_CHECK_EX( nTotalPops + nPostTestPops == nQueueSize, "popped=" << nTotalPops + nPostTestPops << " must be " << nQueueSize ); - CPPUNIT_CHECK( testQueue.empty() ); - - // Test that all items have been popped - // Test FIFO order - CPPUNIT_MSG( " Test consistency of popped sequence..." ); - size_t nErrors = 0; - for ( size_t nWriter = 0; nWriter < s_nWriterThreadCount; ++nWriter ) { - std::vector arrData; - arrData.reserve( m_nThreadPushCount ); - nErrors = 0; - for ( size_t nReader = 0; nReader < arrReaders.size(); ++nReader ) { - ReaderIterator it = arrReaders[nReader]->m_WriterData[nWriter].begin(); - ReaderIterator itEnd = arrReaders[nReader]->m_WriterData[nWriter].end(); - if ( it != itEnd ) { - ReaderIterator itPrev = it; - for ( ++it; it != itEnd; ++it ) { - CPPUNIT_CHECK_EX( *itPrev < *it + nRightOffset, - "Reader " << nReader << ", Writer " << nWriter << ": prev=" << *itPrev << ", cur=" << *it ); - if ( ++nErrors > 10 ) - return; - itPrev = it; - } - } - - for ( it = arrReaders[nReader]->m_WriterData[nWriter].begin(); it != itEnd; ++it ) - arrData.push_back( *it ); - } - std::sort( arrData.begin(), arrData.end() ); - nErrors = 0; - for ( size_t i=1; i < arrData.size(); ++i ) { - if ( arrData[i-1] + 1 != arrData[i] ) { - CPPUNIT_CHECK_EX( arrData[i-1] + 1 == arrData[i], "Writer " << nWriter << ": [" << (i-1) << "]=" << arrData[i-1] << ", [" << i << "]=" << arrData[i] ); - if ( ++nErrors > 10 ) - return; - } - } - - CPPUNIT_CHECK_EX( arrData[0] == 0, "Writer " << nWriter << "[0] != 0" ); - CPPUNIT_CHECK_EX( arrData[arrData.size() - 1] == m_nThreadPushCount - 1, "Writer " << nWriter << "[last] != " << m_nThreadPushCount - 1 ); - } - } - - template - void test_with( Queue& testQueue, value_array& arrValue, size_t nLeftOffset, size_t nRightOffset ) - { - m_nThreadPushCount = s_nQueueSize / s_nWriterThreadCount; - CPPUNIT_MSG( " reader count=" << s_nReaderThreadCount << " writer count=" << s_nWriterThreadCount - << " item count=" << m_nThreadPushCount * s_nWriterThreadCount << "..." ); - - typename Queue::value_type * pValStart = arrValue.get(); - typename Queue::value_type * pValEnd = pValStart + s_nQueueSize; - - CppUnitMini::ThreadPool pool( *this ); - - m_nProducerCount.store( s_nWriterThreadCount, atomics::memory_order_release ); - - // Writers must be first - pool.add( new Producer( pool, testQueue ), s_nWriterThreadCount ); - { - for ( typename Queue::value_type * it = pValStart; it != pValEnd; ++it ) { - it->nNo = 0; - it->nWriterNo = 0; - it->nConsumer = c_nBadConsumer; - } - - typename Queue::value_type * pStart = pValStart; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - static_cast* >( *it )->m_pStart = pStart; - pStart += m_nThreadPushCount; - static_cast* >( *it )->m_pEnd = pStart; - } - } - pool.add( new Consumer( pool, testQueue ), s_nReaderThreadCount ); - - pool.run(); - - // Check that all values have been dequeued - { - size_t nBadConsumerCount = 0; - size_t nQueueSize = m_nThreadPushCount * s_nWriterThreadCount; - typename Queue::value_type * pEnd = pValStart + nQueueSize; - for ( typename Queue::value_type * it = pValStart; it != pEnd; ++it ) { - if ( it->nConsumer == c_nBadConsumer ) - ++nBadConsumerCount; - } - CPPUNIT_CHECK_EX( nBadConsumerCount == 0, "nBadConsumerCount=" << nBadConsumerCount ); - } - - analyze( pool, testQueue, nLeftOffset, nRightOffset ); - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test() - { - value_array arrValue( s_nQueueSize ); - { - { - Queue q; - test_with( q, arrValue, 0, 0 ); - } - Queue::gc::force_dispose(); - } - } - - template - void test_boost() - { - value_array arrValue( s_nQueueSize ); - { - Queue q; - test_with(q, arrValue, 0, 0); - } - } - - template - void test_bounded() - { - value_array arrValue( s_nQueueSize ); - Queue q; - test_with(q, arrValue, 0, 0); - } - - template - void test_fcqueue() - { - value_array arrValue( s_nQueueSize ); - CPPUNIT_MSG( "Combining pass count: " << s_nFCPassCount << ", compact factor: " << s_nFCCompactFactor ); - Queue q( s_nFCCompactFactor, s_nFCPassCount ); - test_with(q, arrValue, 0, 0); - } - - template - void test_segmented() - { - value_array arrValue( s_nQueueSize ); - for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { - CPPUNIT_MSG( "Segment size: " << nSegmentSize ); - { - Queue q( nSegmentSize ); - test_with( q, arrValue, nSegmentSize * 2, nSegmentSize ); - } - Queue::gc::force_dispose(); - } - } - - template - void test_spqueue() - { - value_array arrValue( s_nQueueSize ); - for ( size_t nArraySize = 2; nArraySize <= 64; nArraySize *= 2 ) { - CPPUNIT_MSG( "Array size: " << nArraySize ); - { - Queue q( nArraySize ); - test_with( q, arrValue, 0, 0 ); - } - Queue::gc::force_dispose(); - } - } - - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nReaderThreadCount = cfg.getULong("ReaderCount", 4 ); - s_nWriterThreadCount = cfg.getULong("WriterCount", 4 ); - s_nQueueSize = cfg.getULong("QueueSize", 10000000 ); - s_nFCPassCount = cfg.getUInt("FCPassCount", 8); - s_nFCCompactFactor = cfg.getUInt("FCCompactFactor", 64); - } - - protected: - CDSUNIT_DECLARE_MSQueue - CDSUNIT_DECLARE_MoirQueue - CDSUNIT_DECLARE_OptimisticQueue - CDSUNIT_DECLARE_BasketQueue - CDSUNIT_DECLARE_FCQueue - CDSUNIT_DECLARE_SegmentedQueue - CDSUNIT_DECLARE_TsigasCycleQueue - CDSUNIT_DECLARE_VyukovMPMCCycleQueue - CDSUNIT_DECLARE_BoostSList - - - CPPUNIT_TEST_SUITE(IntrusiveQueue_ReaderWriter) - CDSUNIT_TEST_MSQueue - CDSUNIT_TEST_MoirQueue - CDSUNIT_TEST_OptimisticQueue - CDSUNIT_TEST_BasketQueue - CDSUNIT_TEST_FCQueue - CDSUNIT_TEST_SegmentedQueue - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CDSUNIT_TEST_BoostSList - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::IntrusiveQueue_ReaderWriter); diff --git a/tests/unit/queue/queue_defs.h b/tests/unit/queue/queue_defs.h deleted file mode 100644 index 18739fba..00000000 --- a/tests/unit/queue/queue_defs.h +++ /dev/null @@ -1,275 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef CDSUNIT_QUEUE_DEFS_H -#define CDSUNIT_QUEUE_DEFS_H - -// MoirQueue -#define CDSUNIT_DECLARE_MoirQueue( ITEM_TYPE ) \ - TEST_CASE( MoirQueue_HP, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_HP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_HP_seqcst, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_HP_ic, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_HP_stat, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_DHP, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_DHP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_DHP_seqcst, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_DHP_ic, ITEM_TYPE ) \ - TEST_CASE( MoirQueue_DHP_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_MoirQueue \ - CPPUNIT_TEST(MoirQueue_HP) \ - CPPUNIT_TEST(MoirQueue_HP_michaelAlloc) \ - CPPUNIT_TEST(MoirQueue_HP_seqcst) \ - CPPUNIT_TEST(MoirQueue_HP_ic) \ - CPPUNIT_TEST(MoirQueue_HP_stat) \ - CPPUNIT_TEST(MoirQueue_DHP) \ - CPPUNIT_TEST(MoirQueue_DHP_michaelAlloc) \ - CPPUNIT_TEST(MoirQueue_DHP_seqcst) \ - CPPUNIT_TEST(MoirQueue_DHP_ic) \ - CPPUNIT_TEST(MoirQueue_DHP_stat) - -// MSQueue -#define CDSUNIT_DECLARE_MSQueue( ITEM_TYPE ) \ - TEST_CASE( MSQueue_HP, ITEM_TYPE ) \ - TEST_CASE( MSQueue_HP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( MSQueue_HP_seqcst, ITEM_TYPE ) \ - TEST_CASE( MSQueue_HP_ic, ITEM_TYPE ) \ - TEST_CASE( MSQueue_HP_stat, ITEM_TYPE ) \ - TEST_CASE( MSQueue_DHP, ITEM_TYPE ) \ - TEST_CASE( MSQueue_DHP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( MSQueue_DHP_seqcst, ITEM_TYPE ) \ - TEST_CASE( MSQueue_DHP_ic, ITEM_TYPE ) \ - TEST_CASE( MSQueue_DHP_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_MSQueue \ - CPPUNIT_TEST(MSQueue_HP) \ - CPPUNIT_TEST(MSQueue_HP_michaelAlloc) \ - CPPUNIT_TEST(MSQueue_HP_seqcst) \ - CPPUNIT_TEST(MSQueue_HP_ic) \ - CPPUNIT_TEST(MSQueue_HP_stat) \ - CPPUNIT_TEST(MSQueue_DHP) \ - CPPUNIT_TEST(MSQueue_DHP_michaelAlloc) \ - CPPUNIT_TEST(MSQueue_DHP_seqcst) \ - CPPUNIT_TEST(MSQueue_DHP_ic) \ - CPPUNIT_TEST(MSQueue_DHP_stat) - - -// OptimisticQueue -#define CDSUNIT_DECLARE_OptimisticQueue( ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_HP, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_HP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_HP_seqcst, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_HP_ic, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_HP_stat, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_DHP, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_DHP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_DHP_seqcst, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_DHP_ic, ITEM_TYPE ) \ - TEST_CASE(OptimisticQueue_DHP_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_OptimisticQueue \ - CPPUNIT_TEST(OptimisticQueue_HP) \ - CPPUNIT_TEST(OptimisticQueue_HP_michaelAlloc) \ - CPPUNIT_TEST(OptimisticQueue_HP_seqcst) \ - CPPUNIT_TEST(OptimisticQueue_HP_ic) \ - CPPUNIT_TEST(OptimisticQueue_HP_stat) \ - CPPUNIT_TEST(OptimisticQueue_DHP) \ - CPPUNIT_TEST(OptimisticQueue_DHP_michaelAlloc) \ - CPPUNIT_TEST(OptimisticQueue_DHP_seqcst) \ - CPPUNIT_TEST(OptimisticQueue_DHP_ic) \ - CPPUNIT_TEST(OptimisticQueue_DHP_stat) - - -// BasketQueue -#define CDSUNIT_DECLARE_BasketQueue( ITEM_TYPE ) \ - TEST_CASE( BasketQueue_HP, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_HP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_HP_seqcst, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_HP_ic, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_HP_stat, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_DHP, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_DHP_michaelAlloc, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_DHP_seqcst, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_DHP_ic, ITEM_TYPE ) \ - TEST_CASE( BasketQueue_DHP_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_BasketQueue \ - CPPUNIT_TEST(BasketQueue_HP) \ - CPPUNIT_TEST(BasketQueue_HP_michaelAlloc) \ - CPPUNIT_TEST(BasketQueue_HP_seqcst) \ - CPPUNIT_TEST(BasketQueue_HP_ic) \ - CPPUNIT_TEST(BasketQueue_HP_stat) \ - CPPUNIT_TEST(BasketQueue_DHP) \ - CPPUNIT_TEST(BasketQueue_DHP_michaelAlloc) \ - CPPUNIT_TEST(BasketQueue_DHP_seqcst) \ - CPPUNIT_TEST(BasketQueue_DHP_ic) \ - CPPUNIT_TEST(BasketQueue_DHP_stat) - - -// FCQueue -#define CDSUNIT_DECLARE_FCQueue( ITEM_TYPE ) \ - TEST_CASE( FCQueue_deque, ITEM_TYPE ) \ - TEST_CASE( FCQueue_deque_elimination, ITEM_TYPE ) \ - TEST_CASE( FCQueue_deque_elimination_stat, ITEM_TYPE ) \ - TEST_CASE( FCQueue_list, ITEM_TYPE ) \ - TEST_CASE( FCQueue_list_elimination, ITEM_TYPE ) \ - TEST_CASE( FCQueue_list_elimination_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_FCQueue \ - CPPUNIT_TEST( FCQueue_deque) \ - CPPUNIT_TEST( FCQueue_deque_elimination) \ - CPPUNIT_TEST( FCQueue_deque_elimination_stat) \ - CPPUNIT_TEST( FCQueue_list) \ - CPPUNIT_TEST( FCQueue_list_elimination) \ - CPPUNIT_TEST( FCQueue_list_elimination_stat) - - -// FCDeque -#define CDSUNIT_DECLARE_FCDeque( ITEM_TYPE ) \ - TEST_CASE( FCDequeL_default, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_mutex, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_elimination, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_elimination_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_boost, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_boost_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_boost_elimination, ITEM_TYPE ) \ - TEST_CASE( FCDequeL_boost_elimination_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_default, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_mutex, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_elimination, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_elimination_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_boost, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_boost_stat, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_boost_elimination, ITEM_TYPE ) \ - TEST_CASE( FCDequeR_boost_elimination_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_FCDeque \ - CPPUNIT_TEST( FCDequeL_default ) \ - CPPUNIT_TEST( FCDequeL_mutex ) \ - CPPUNIT_TEST( FCDequeL_stat ) \ - CPPUNIT_TEST( FCDequeL_elimination ) \ - CPPUNIT_TEST( FCDequeL_elimination_stat ) \ - CPPUNIT_TEST( FCDequeL_boost ) \ - CPPUNIT_TEST( FCDequeL_boost_stat ) \ - CPPUNIT_TEST( FCDequeL_boost_elimination ) \ - CPPUNIT_TEST( FCDequeL_boost_elimination_stat ) \ - CPPUNIT_TEST( FCDequeR_default ) \ - CPPUNIT_TEST( FCDequeR_mutex ) \ - CPPUNIT_TEST( FCDequeR_stat ) \ - CPPUNIT_TEST( FCDequeR_elimination ) \ - CPPUNIT_TEST( FCDequeR_elimination_stat ) \ - CPPUNIT_TEST( FCDequeR_boost ) \ - CPPUNIT_TEST( FCDequeR_boost_stat ) \ - CPPUNIT_TEST( FCDequeR_boost_elimination ) \ - CPPUNIT_TEST( FCDequeR_boost_elimination_stat ) - - -// RWQueue -#define CDSUNIT_DECLARE_RWQueue( ITEM_TYPE ) \ - TEST_CASE( RWQueue_Spin, ITEM_TYPE ) \ - TEST_CASE( RWQueue_Spin_ic, ITEM_TYPE ) \ - TEST_CASE( RWQueue_mutex, ITEM_TYPE ) - -#define CDSUNIT_TEST_RWQueue \ - CPPUNIT_TEST(RWQueue_Spin) \ - CPPUNIT_TEST(RWQueue_Spin_ic) \ - CPPUNIT_TEST(RWQueue_mutex) - -// TsigasCycleQueue -#define CDSUNIT_DECLARE_TsigasCycleQueue( ITEM_TYPE ) \ - TEST_BOUNDED(TsigasCycleQueue_dyn, ITEM_TYPE) \ - TEST_BOUNDED(TsigasCycleQueue_dyn_michaelAlloc, ITEM_TYPE) \ - TEST_BOUNDED(TsigasCycleQueue_dyn_ic, ITEM_TYPE) - -#define CDSUNIT_TEST_TsigasCycleQueue \ - CPPUNIT_TEST(TsigasCycleQueue_dyn) \ - CPPUNIT_TEST(TsigasCycleQueue_dyn_michaelAlloc) \ - CPPUNIT_TEST(TsigasCycleQueue_dyn_ic) - - -// VyukovMPMCCycleQueue -#define CDSUNIT_DECLARE_VyukovMPMCCycleQueue( ITEM_TYPE ) \ - TEST_BOUNDED(VyukovMPMCCycleQueue_dyn, ITEM_TYPE) \ - TEST_BOUNDED(VyukovMPMCCycleQueue_dyn_michaelAlloc, ITEM_TYPE) \ - TEST_BOUNDED(VyukovMPMCCycleQueue_dyn_ic, ITEM_TYPE) \ - - -#define CDSUNIT_TEST_VyukovMPMCCycleQueue \ - CPPUNIT_TEST(VyukovMPMCCycleQueue_dyn) \ - CPPUNIT_TEST(VyukovMPMCCycleQueue_dyn_michaelAlloc) \ - CPPUNIT_TEST(VyukovMPMCCycleQueue_dyn_ic) \ - -// SegmentedQueue -#define CDSUNIT_DECLARE_SegmentedQueue( ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_spin, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_spin_padding, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_spin_stat, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex_padding, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_HP_mutex_stat, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin_padding, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_spin_stat, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex_padding, ITEM_TYPE ) \ - TEST_SEGMENTED( SegmentedQueue_DHP_mutex_stat, ITEM_TYPE ) - -#define CDSUNIT_TEST_SegmentedQueue \ - CPPUNIT_TEST( SegmentedQueue_HP_spin ) \ - CPPUNIT_TEST( SegmentedQueue_HP_spin_padding ) \ - CPPUNIT_TEST( SegmentedQueue_HP_spin_stat ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex_padding ) \ - CPPUNIT_TEST( SegmentedQueue_HP_mutex_stat ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin_padding ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_spin_stat ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex_padding ) \ - CPPUNIT_TEST( SegmentedQueue_DHP_mutex_stat ) - -// std::queue -#define CDSUNIT_DECLARE_StdQueue( ITEM_TYPE ) \ - TEST_CASE( StdQueue_deque_Spinlock, ITEM_TYPE ) \ - TEST_CASE( StdQueue_list_Spinlock, ITEM_TYPE ) \ - TEST_CASE( StdQueue_deque_BoostMutex, ITEM_TYPE ) \ - TEST_CASE( StdQueue_list_BoostMutex, ITEM_TYPE ) - -#define CDSUNIT_TEST_StdQueue \ - CPPUNIT_TEST(StdQueue_deque_Spinlock) \ - CPPUNIT_TEST(StdQueue_list_Spinlock) \ - CPPUNIT_TEST(StdQueue_deque_BoostMutex) \ - CPPUNIT_TEST(StdQueue_list_BoostMutex) - - -#endif // #ifndef CDSUNIT_QUEUE_DEFS_H diff --git a/tests/unit/queue/queue_pop.cpp b/tests/unit/queue/queue_pop.cpp deleted file mode 100644 index bcb4e5f9..00000000 --- a/tests/unit/queue/queue_pop.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/queue_type.h" -#include "queue/queue_defs.h" - -// Multi-threaded queue test for pop operation -namespace queue { - -#define TEST_CASE( Q, V ) void Q() { test< Types::Q >(); } -#define TEST_BOUNDED( Q, V ) void Q() { test_bounded< Types::Q >(); } -#define TEST_SEGMENTED( Q, V ) void Q() { test_segmented< Types::Q >(); } - - namespace ns_Queue_Pop { - static size_t s_nThreadCount = 8; - static size_t s_nQueueSize = 20000000 ; // no more than 20 million records - - struct SimpleValue { - size_t nNo; - - SimpleValue(): nNo(0) {} - SimpleValue( size_t n ): nNo(n) {} - size_t getNo() const { return nNo; } - }; - } - using namespace ns_Queue_Pop; - - class Queue_Pop: public CppUnitMini::TestCase - { - template - class Thread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Thread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - long * m_arr; - size_t m_nPopCount; - - public: - Thread( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - { - m_arr = new long[s_nQueueSize]; - } - Thread( Thread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - { - m_arr = new long[s_nQueueSize]; - } - ~Thread() - { - delete [] m_arr; - } - - Queue_Pop& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - memset(m_arr, 0, sizeof(m_arr[0]) * s_nQueueSize ); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_fTime = m_Timer.duration(); - - typedef typename Queue::value_type value_type; - value_type value = value_type(); - size_t nPopCount = 0; - while ( m_Queue.pop( value ) ) { - ++m_arr[ value.getNo() ]; - ++nPopCount; - } - m_nPopCount = nPopCount; - - m_fTime = m_Timer.duration() - m_fTime; - } - }; - - protected: - - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue ) - { - size_t * arr = new size_t[ s_nQueueSize ]; - memset(arr, 0, sizeof(arr[0]) * s_nQueueSize ); - - double fTime = 0; - size_t nTotalPops = 0; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - for ( size_t i = 0; i < s_nQueueSize; ++i ) - arr[i] += pThread->m_arr[i]; - nTotalPops += pThread->m_nPopCount; - fTime += pThread->m_fTime; - } - CPPUNIT_MSG( " Duration=" << (fTime / s_nThreadCount) ); - CPPUNIT_CHECK_EX( nTotalPops == s_nQueueSize, "Total pop=" << nTotalPops << ", queue size=" << s_nQueueSize); - CPPUNIT_CHECK( testQueue.empty() ) - - size_t nError = 0; - for ( size_t i = 0; i < s_nQueueSize; ++i ) { - if ( arr[i] != 1 ) { - CPPUNIT_MSG( " ERROR: Item " << i << " has not been popped" ); - CPPUNIT_ASSERT( ++nError <= 10 ); - } - } - - delete [] arr; - } - - template - void test() - { - Queue testQueue; - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - CPPUNIT_MSG( " Create queue size =" << s_nQueueSize << " ..."); - cds::OS::Timer timer; - for ( size_t i = 0; i < s_nQueueSize; ++i ) - testQueue.push( i ); - CPPUNIT_MSG( " Duration=" << timer.duration() ); - - CPPUNIT_MSG( " Pop test, thread count=" << s_nThreadCount << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_bounded() - { - Queue testQueue( s_nQueueSize ); - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - CPPUNIT_MSG( " Create queue size =" << s_nQueueSize << " ..."); - cds::OS::Timer timer; - for ( size_t i = 0; i < s_nQueueSize; ++i ) - testQueue.push( i ); - CPPUNIT_MSG( " Duration=" << timer.duration() ); - - CPPUNIT_MSG( " Pop test, thread count=" << s_nThreadCount << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_segmented() - { - for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { - CPPUNIT_MSG( "Segment size: " << nSegmentSize ); - - Queue testQueue( nSegmentSize ); - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - CPPUNIT_MSG( " Create queue size =" << s_nQueueSize << " ..."); - cds::OS::Timer timer; - for ( size_t i = 0; i < s_nQueueSize; ++i ) - testQueue.push( i ); - CPPUNIT_MSG( " Duration=" << timer.duration() ); - - CPPUNIT_MSG( " Pop test, thread count=" << s_nThreadCount << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - } - - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nThreadCount = cfg.getULong("ThreadCount", 8 ); - s_nQueueSize = cfg.getULong("QueueSize", 20000000 ); - } - - protected: - CDSUNIT_DECLARE_MoirQueue( SimpleValue ) - CDSUNIT_DECLARE_MSQueue( SimpleValue ) - CDSUNIT_DECLARE_OptimisticQueue( SimpleValue ) - CDSUNIT_DECLARE_BasketQueue( SimpleValue ) - CDSUNIT_DECLARE_FCQueue( SimpleValue ) - CDSUNIT_DECLARE_FCDeque( SimpleValue ) - CDSUNIT_DECLARE_SegmentedQueue( SimpleValue ) - CDSUNIT_DECLARE_RWQueue( SimpleValue ) - CDSUNIT_DECLARE_TsigasCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_VyukovMPMCCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_StdQueue( SimpleValue ) - - CPPUNIT_TEST_SUITE(Queue_Pop) - CDSUNIT_TEST_MoirQueue - CDSUNIT_TEST_MSQueue - CDSUNIT_TEST_OptimisticQueue - CDSUNIT_TEST_BasketQueue - CDSUNIT_TEST_FCQueue - CDSUNIT_TEST_FCDeque - CDSUNIT_TEST_SegmentedQueue - CDSUNIT_TEST_RWQueue - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CDSUNIT_TEST_StdQueue - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::Queue_Pop); diff --git a/tests/unit/queue/queue_push.cpp b/tests/unit/queue/queue_push.cpp deleted file mode 100644 index bce48485..00000000 --- a/tests/unit/queue/queue_push.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/queue_type.h" -#include "queue/queue_defs.h" - - -// Multi-threaded queue test for push operation -namespace queue { - -#define TEST_CASE( Q, V ) void Q() { test< Types::Q >(); } -#define TEST_BOUNDED( Q, V ) void Q() { test_bounded< Types::Q >(); } -#define TEST_SEGMENTED( Q, V ) void Q() { test_segmented< Types::Q >(); } - - namespace ns_Queue_Push { - static size_t s_nThreadCount = 8; - static size_t s_nQueueSize = 20000000 ; // no more than 20 million records - - struct SimpleValue { - size_t nNo; - - SimpleValue(): nNo(0) {} - SimpleValue( size_t n ): nNo(n) {} - size_t getNo() const { return nNo; } - }; - } - using namespace ns_Queue_Push; - - class Queue_Push: public CppUnitMini::TestCase - { - template - class Thread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Thread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nStartItem; - size_t m_nEndItem; - size_t m_nPushError; - - public: - Thread( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - {} - Thread( Thread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - {} - - Queue_Push& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_fTime = m_Timer.duration(); - - m_nPushError = 0; - for ( size_t nItem = m_nStartItem; nItem < m_nEndItem; ++nItem ) { - if ( !m_Queue.push( nItem )) - ++m_nPushError; - } - - m_fTime = m_Timer.duration() - m_fTime; - } - }; - - protected: - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue ) - { - size_t nThreadItems = s_nQueueSize / s_nThreadCount; - double fTime = 0; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - fTime += pThread->m_fTime; - if ( pThread->m_nPushError != 0 ) - CPPUNIT_MSG(" ERROR: thread push error count=" << pThread->m_nPushError ); - } - CPPUNIT_MSG( " Duration=" << (fTime / s_nThreadCount) ); - CPPUNIT_CHECK( !testQueue.empty() ) - - size_t * arr = new size_t[ s_nQueueSize ]; - memset(arr, 0, sizeof(arr[0]) * s_nQueueSize ); - - cds::OS::Timer timer; - CPPUNIT_MSG( " Pop (single-threaded)..." ); - size_t nPopped = 0; - SimpleValue val = SimpleValue(); - while ( testQueue.pop( val )) { - nPopped++; - ++arr[ val.getNo() ]; - } - CPPUNIT_MSG( " Duration=" << timer.duration() ); - - size_t nTotalItems = nThreadItems * s_nThreadCount; - size_t nError = 0; - for ( size_t i = 0; i < nTotalItems; ++i ) { - if ( arr[i] != 1 ) { - CPPUNIT_MSG( " ERROR: Item " << i << " has not been pushed" ); - CPPUNIT_ASSERT( ++nError <= 10 ); - } - } - - delete [] arr; - } - - template - void test() - { - Queue testQueue; - - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - size_t nStart = 0; - size_t nThreadItemCount = s_nQueueSize / s_nThreadCount; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - pThread->m_nStartItem = nStart; - nStart += nThreadItemCount; - pThread->m_nEndItem = nStart; - } - - CPPUNIT_MSG( " Push test, thread count=" << s_nThreadCount << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_bounded() - { - size_t nStart = 0; - size_t nThreadItemCount = s_nQueueSize / s_nThreadCount; - - Queue testQueue( s_nQueueSize ); - - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - pThread->m_nStartItem = nStart; - nStart += nThreadItemCount; - pThread->m_nEndItem = nStart; - } - - CPPUNIT_MSG( " Push test, thread count=" << s_nThreadCount << " ..."); - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_segmented() - { - CPPUNIT_MSG( " Push test, thread count=" << s_nThreadCount << " ..."); - for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { - CPPUNIT_MSG( "Segment size: " << nSegmentSize ); - - Queue testQueue( nSegmentSize ); - - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - size_t nStart = 0; - size_t nThreadItemCount = s_nQueueSize / s_nThreadCount; - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = reinterpret_cast *>(*it); - pThread->m_nStartItem = nStart; - nStart += nThreadItemCount; - pThread->m_nEndItem = nStart; - } - - pool.run(); - - analyze( pool, testQueue ); - - CPPUNIT_MSG( testQueue.statistics() ); - } - } - - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nThreadCount = cfg.getULong("ThreadCount", 8 ); - s_nQueueSize = cfg.getULong("QueueSize", 20000000 ); - } - - protected: - CDSUNIT_DECLARE_MoirQueue( SimpleValue ) - CDSUNIT_DECLARE_MSQueue( SimpleValue ) - CDSUNIT_DECLARE_OptimisticQueue( SimpleValue ) - CDSUNIT_DECLARE_BasketQueue( SimpleValue ) - CDSUNIT_DECLARE_FCQueue( SimpleValue ) - CDSUNIT_DECLARE_FCDeque( SimpleValue ) - CDSUNIT_DECLARE_SegmentedQueue( SimpleValue ) - CDSUNIT_DECLARE_RWQueue( SimpleValue ) - CDSUNIT_DECLARE_TsigasCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_VyukovMPMCCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_StdQueue( SimpleValue ) - - CPPUNIT_TEST_SUITE(Queue_Push) - CDSUNIT_TEST_MoirQueue - CDSUNIT_TEST_MSQueue - CDSUNIT_TEST_OptimisticQueue - CDSUNIT_TEST_BasketQueue - CDSUNIT_TEST_FCQueue - CDSUNIT_TEST_FCDeque - CDSUNIT_TEST_SegmentedQueue - CDSUNIT_TEST_RWQueue - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CDSUNIT_TEST_StdQueue - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::Queue_Push); diff --git a/tests/unit/queue/queue_random.cpp b/tests/unit/queue/queue_random.cpp deleted file mode 100644 index ab785803..00000000 --- a/tests/unit/queue/queue_random.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/queue_type.h" -#include "queue/queue_defs.h" - - -#include -#include - -// Multi-threaded queue test for random push/pop operation -namespace queue { - -#define TEST_CASE( Q, V ) void Q() { test< Types::Q >(); } -#define TEST_BOUNDED( Q, V ) TEST_CASE( Q, V ) -#define TEST_SEGMENTED( Q, V ) void Q() { test_segmented< Types< V >::Q >(); } - - namespace ns_Queue_Random { - static size_t s_nThreadCount = 16; - static size_t s_nQueueSize = 10000000; - - struct SimpleValue { - size_t nNo; - size_t nThread; - - SimpleValue() {} - SimpleValue( size_t n ): nNo(n) {} - size_t getNo() const { return nNo; } - }; - } - - using namespace ns_Queue_Random; - - class Queue_Random: public CppUnitMini::TestCase - { - typedef CppUnitMini::TestCase base_class; - - template - class Thread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new Thread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - - size_t m_nPushCount; - size_t m_nPopCount; - size_t m_nEmptyPop; - - size_t m_nUndefWriter; - size_t m_nRepeatValue; - size_t m_nPushError ; // push error count - - std::vector m_arrLastRead; - std::vector m_arrPopCountPerThread; - - size_t const m_nSpread; - - public: - Thread( CppUnitMini::ThreadPool& pool, Queue& q, size_t nSpread = 0 ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - , m_nSpread( nSpread ) - {} - Thread( Thread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - , m_nSpread( src.m_nSpread ) - {} - - Queue_Random& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - m_nPushCount = - m_nPopCount = - m_nEmptyPop = - m_nUndefWriter = - m_nRepeatValue = - m_nPushError = 0; - - m_arrLastRead.resize( s_nThreadCount, 0 ); - m_arrPopCountPerThread.resize( s_nThreadCount, 0 ); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - size_t const nThreadCount = s_nThreadCount; - size_t const nTotalPush = getTest().m_nThreadPushCount; - - SimpleValue node; - - m_fTime = m_Timer.duration(); - - bool bNextPop = false; - while ( m_nPushCount < nTotalPush ) { - if ( !bNextPop && (rand() & 3) != 3 ) { - // push - node.nThread = m_nThreadNo; - node.nNo = ++m_nPushCount; - if ( !m_Queue.push( node )) { - ++m_nPushError; - --m_nPushCount; - } - - } - else { - // pop - pop( nThreadCount ); - bNextPop = false; - } - } - - size_t nPopLoop = 0; - while ( !m_Queue.empty() && nPopLoop < 1000000 ) { - if ( pop( nThreadCount ) ) - nPopLoop = 0; - else - ++nPopLoop; - } - - - m_fTime = m_Timer.duration() - m_fTime; - } - - bool pop( size_t nThreadCount ) - { - SimpleValue node; - node.nThread = -1; - node.nNo = -1; - if ( m_Queue.pop( node )) { - ++m_nPopCount; - if ( node.nThread < nThreadCount ) { - m_arrPopCountPerThread[ node.nThread ] += 1; - if ( m_nSpread ) { - if ( m_arrLastRead[ node.nThread ] > node.nNo ) { - if ( m_arrLastRead[ node.nThread ] - node.nNo > m_nSpread ) - ++m_nRepeatValue; - } - else if ( m_arrLastRead[ node.nThread ] == node.nNo ) - ++m_nRepeatValue; - m_arrLastRead[ node.nThread ] = node.nNo; - } - else { - if ( m_arrLastRead[ node.nThread ] < node.nNo ) { - m_arrLastRead[ node.nThread ] = node.nNo; - } - else - ++m_nRepeatValue; - } - - //if ( node.nNo < m_Test.m_nPushCount ) - // m_Test.m_pRead[ node.nWriter ][ node.nNo ] = node.nNo; - } - else { - ++m_nUndefWriter; - } - } - else { - ++m_nEmptyPop; - return false; - } - return true; - } - }; - - protected: - size_t m_nThreadPushCount; - - protected: - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue ) - { - CPPUNIT_CHECK( testQueue.empty() ); - - std::vector< size_t > arrPushCount; - arrPushCount.resize( s_nThreadCount, 0 ); - - size_t nPushTotal = 0; - size_t nPopTotal = 0; - double fTime = 0; - size_t nPushError = 0; - - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Thread * pThread = static_cast *>( *it ); - CPPUNIT_CHECK( pThread->m_nUndefWriter == 0 ); - CPPUNIT_CHECK_EX( pThread->m_nRepeatValue == 0, "nRepeatValue=" << pThread->m_nRepeatValue ); - if ( !boost::is_base_of::value ) { - CPPUNIT_CHECK( pThread->m_nPushError == 0 ); - } - else - nPushError += pThread->m_nPushError; - - arrPushCount[ pThread->m_nThreadNo ] += pThread->m_nPushCount; - - nPushTotal += pThread->m_nPushCount; - nPopTotal += pThread->m_nPopCount; - fTime += pThread->m_fTime; - } - - CPPUNIT_MSG( " Duration=" << (fTime /= s_nThreadCount) ); - if ( boost::is_base_of::value ) { - CPPUNIT_MSG( " push error (when queue is full)=" << nPushError ); - } - - size_t nTotalItems = m_nThreadPushCount * s_nThreadCount; - - CPPUNIT_CHECK_EX( nPushTotal == nTotalItems, "nPushTotal=" << nPushTotal << ", nTotalItems=" << nTotalItems ); - CPPUNIT_CHECK_EX( nPopTotal == nTotalItems, "nPopTotal=" << nPopTotal << ", nTotalItems=" << nTotalItems ); - - for ( size_t i = 0; i < s_nThreadCount; ++i ) - CPPUNIT_CHECK( arrPushCount[i] == m_nThreadPushCount ); - } - - template - void test() - { - CPPUNIT_MSG( "Random push/pop test\n thread count=" << s_nThreadCount << ", push count=" << s_nQueueSize << " ..." ); - - m_nThreadPushCount = s_nQueueSize / s_nThreadCount; - - Queue testQueue; - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue ), s_nThreadCount ); - - pool.run(); - - analyze( pool, testQueue ); - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_segmented() - { - CPPUNIT_MSG( "Random push/pop test\n thread count=" << s_nThreadCount << ", push count=" << s_nQueueSize << " ..." ); - - m_nThreadPushCount = s_nQueueSize / s_nThreadCount; - - for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { - CPPUNIT_MSG( "Segment size: " << nSegmentSize ); - - Queue testQueue( nSegmentSize ); - CppUnitMini::ThreadPool pool( *this ); - pool.add( new Thread( pool, testQueue, nSegmentSize * 2 ), s_nThreadCount ); - - pool.run(); - - analyze( pool, testQueue ); - CPPUNIT_MSG( testQueue.statistics() ); - } - } - - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nThreadCount = cfg.getULong("ThreadCount", 8 ); - s_nQueueSize = cfg.getULong("QueueSize", 20000000 ); - } - - protected: - CDSUNIT_DECLARE_MoirQueue( SimpleValue ) - CDSUNIT_DECLARE_MSQueue( SimpleValue ) - CDSUNIT_DECLARE_OptimisticQueue( SimpleValue ) - CDSUNIT_DECLARE_BasketQueue( SimpleValue ) - CDSUNIT_DECLARE_FCQueue( SimpleValue ) - CDSUNIT_DECLARE_FCDeque( SimpleValue ) - CDSUNIT_DECLARE_SegmentedQueue( SimpleValue ) - CDSUNIT_DECLARE_RWQueue( SimpleValue ) - CDSUNIT_DECLARE_TsigasCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_VyukovMPMCCycleQueue( SimpleValue ) - CDSUNIT_DECLARE_StdQueue( SimpleValue ) - - CPPUNIT_TEST_SUITE(Queue_Random) - CDSUNIT_TEST_MoirQueue - CDSUNIT_TEST_MSQueue - CDSUNIT_TEST_OptimisticQueue - CDSUNIT_TEST_BasketQueue - CDSUNIT_TEST_FCQueue - CDSUNIT_TEST_FCDeque - CDSUNIT_TEST_SegmentedQueue - CDSUNIT_TEST_RWQueue - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CDSUNIT_TEST_StdQueue - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::Queue_Random); diff --git a/tests/unit/queue/queue_reader_writer.cpp b/tests/unit/queue/queue_reader_writer.cpp deleted file mode 100644 index 742e0eba..00000000 --- a/tests/unit/queue/queue_reader_writer.cpp +++ /dev/null @@ -1,394 +0,0 @@ -/* - This file is a part of libcds - Concurrent Data Structures library - - (C) Copyright Maxim Khizhinsky (libcds.dev@gmail.com) 2006-2016 - - Source code repo: http://github.com/khizmax/libcds/ - Download: http://sourceforge.net/projects/libcds/files/ - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "cppunit/thread.h" -#include "queue/queue_type.h" -#include "queue/queue_defs.h" - -#include -#include - -// Multi-threaded random queue test -namespace queue { - -#define TEST_CASE( Q, V ) void Q() { test< Types::Q >(); } -#define TEST_BOUNDED( Q, V ) TEST_CASE( Q, V ) -#define TEST_SEGMENTED( Q, V ) void Q() { test_segmented< Types< V >::Q >(); } - - namespace { - static size_t s_nReaderThreadCount = 4; - static size_t s_nWriterThreadCount = 4; - static size_t s_nQueueSize = 4000000; - - struct Value { - size_t nNo; - size_t nWriterNo; - }; - } - - class Queue_ReaderWriter: public CppUnitMini::TestCase - { - template - class WriterThread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new WriterThread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nPushFailed; - - public: - WriterThread( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - {} - WriterThread( WriterThread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - {} - - Queue_ReaderWriter& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - size_t nPushCount = getTest().m_nThreadPushCount; - Value v; - v.nWriterNo = m_nThreadNo; - v.nNo = 0; - m_nPushFailed = 0; - - m_fTime = m_Timer.duration(); - - while ( v.nNo < nPushCount ) { - if ( m_Queue.push( v )) - ++v.nNo; - else - ++m_nPushFailed; - } - - m_fTime = m_Timer.duration() - m_fTime; - getTest().m_nWriterDone.fetch_add( 1 ); - } - }; - - template - class ReaderThread: public CppUnitMini::TestThread - { - virtual TestThread * clone() - { - return new ReaderThread( *this ); - } - public: - Queue& m_Queue; - double m_fTime; - size_t m_nPopEmpty; - size_t m_nPopped; - size_t m_nBadWriter; - - typedef std::vector TPoppedData; - typedef std::vector::iterator data_iterator; - typedef std::vector::const_iterator const_data_iterator; - - std::vector m_WriterData; - - private: - void initPoppedData() - { - const size_t nWriterCount = s_nWriterThreadCount; - const size_t nWriterPushCount = getTest().m_nThreadPushCount; - m_WriterData.resize( nWriterCount ); - for ( size_t i = 0; i < nWriterCount; ++i ) - m_WriterData[i].reserve( nWriterPushCount ); - } - - public: - ReaderThread( CppUnitMini::ThreadPool& pool, Queue& q ) - : CppUnitMini::TestThread( pool ) - , m_Queue( q ) - { - initPoppedData(); - } - ReaderThread( ReaderThread& src ) - : CppUnitMini::TestThread( src ) - , m_Queue( src.m_Queue ) - { - initPoppedData(); - } - - Queue_ReaderWriter& getTest() - { - return reinterpret_cast( m_Pool.m_Test ); - } - - virtual void init() - { - cds::threading::Manager::attachThread(); - } - virtual void fini() - { - cds::threading::Manager::detachThread(); - } - - virtual void test() - { - m_nPopEmpty = 0; - m_nPopped = 0; - m_nBadWriter = 0; - const size_t nTotalWriters = s_nWriterThreadCount; - Value v; - - m_fTime = m_Timer.duration(); - - while ( true ) { - if ( m_Queue.pop( v ) ) { - ++m_nPopped; - if ( /*v.nWriterNo >= 0 &&*/ v.nWriterNo < nTotalWriters ) - m_WriterData[ v.nWriterNo ].push_back( v.nNo ); - else - ++m_nBadWriter; - } - else - ++m_nPopEmpty; - - if ( m_Queue.empty() ) { - if ( getTest().m_nWriterDone.load() >= nTotalWriters ) { - if ( m_Queue.empty() ) - break; - } - } - } - - m_fTime = m_Timer.duration() - m_fTime; - } - }; - - protected: - size_t m_nThreadPushCount; - atomics::atomic m_nWriterDone; - - protected: - template - void analyze( CppUnitMini::ThreadPool& pool, Queue& testQueue, size_t /*nLeftOffset*/ = 0, size_t nRightOffset = 0 ) - { - typedef ReaderThread Reader; - typedef WriterThread Writer; - typedef typename Reader::const_data_iterator ReaderIterator; - - size_t nPostTestPops = 0; - { - Value v; - while ( testQueue.pop( v )) - ++nPostTestPops; - } - - double fTimeWriter = 0; - double fTimeReader = 0; - size_t nTotalPops = 0; - size_t nPopFalse = 0; - size_t nPoppedItems = 0; - size_t nPushFailed = 0; - - std::vector< Reader * > arrReaders; - - for ( CppUnitMini::ThreadPool::iterator it = pool.begin(); it != pool.end(); ++it ) { - Reader * pReader = dynamic_cast( *it ); - if ( pReader ) { - fTimeReader += pReader->m_fTime; - nTotalPops += pReader->m_nPopped; - nPopFalse += pReader->m_nPopEmpty; - arrReaders.push_back( pReader ); - CPPUNIT_CHECK_EX( pReader->m_nBadWriter == 0, "reader " << pReader->m_nThreadNo << " bad writer event count=" << pReader->m_nBadWriter ); - - size_t nPopped = 0; - for ( size_t n = 0; n < s_nWriterThreadCount; ++n ) - nPopped += pReader->m_WriterData[n].size(); - - CPPUNIT_MSG( " Reader " << pReader->m_nThreadNo - s_nWriterThreadCount << " popped count=" << nPopped ); - nPoppedItems += nPopped; - } - else { - Writer * pWriter = dynamic_cast( *it ); - CPPUNIT_ASSERT( pWriter != nullptr ); - fTimeWriter += pWriter->m_fTime; - nPushFailed += pWriter->m_nPushFailed; - if ( !boost::is_base_of::value ) { - CPPUNIT_CHECK_EX( pWriter->m_nPushFailed == 0, - "writer " << pWriter->m_nThreadNo << " push failed count=" << pWriter->m_nPushFailed ); - } - } - } - CPPUNIT_CHECK_EX( nTotalPops == nPoppedItems, "nTotalPops=" << nTotalPops << ", nPoppedItems=" << nPoppedItems ); - - CPPUNIT_MSG( " Readers: duration=" << fTimeReader / s_nReaderThreadCount << ", success pop=" << nTotalPops << ", failed pops=" << nPopFalse ); - CPPUNIT_MSG( " Writers: duration=" << fTimeWriter / s_nWriterThreadCount << ", failed push=" << nPushFailed ); - - size_t nQueueSize = m_nThreadPushCount * s_nWriterThreadCount; - CPPUNIT_CHECK_EX( nTotalPops + nPostTestPops == nQueueSize, "popped=" << nTotalPops + nPostTestPops << " must be " << nQueueSize ); - CPPUNIT_CHECK( testQueue.empty() ); - - // Test that all items have been popped - CPPUNIT_MSG( " Test consistency of popped sequence..." ); - for ( size_t nWriter = 0; nWriter < s_nWriterThreadCount; ++nWriter ) { - std::vector arrData; - arrData.reserve( m_nThreadPushCount ); - size_t nErrors = 0; - for ( size_t nReader = 0; nReader < arrReaders.size(); ++nReader ) { - ReaderIterator it = arrReaders[nReader]->m_WriterData[nWriter].begin(); - ReaderIterator itEnd = arrReaders[nReader]->m_WriterData[nWriter].end(); - if ( it != itEnd ) { - ReaderIterator itPrev = it; - for ( ++it; it != itEnd; ++it ) { - CPPUNIT_CHECK_EX( *itPrev < *it + nRightOffset, "Reader " << nReader << ", Writer " << nWriter << ": prev=" << *itPrev << ", cur=" << *it ); - if ( ++nErrors > 10 ) - return; - itPrev = it; - } - } - - for ( it = arrReaders[nReader]->m_WriterData[nWriter].begin(); it != itEnd; ++it ) - arrData.push_back( *it ); - } - - std::sort( arrData.begin(), arrData.end() ); - nErrors = 0; - for ( size_t i=1; i < arrData.size(); ++i ) { - if ( arrData[i-1] + 1 != arrData[i] ) { - CPPUNIT_CHECK_EX( arrData[i-1] + 1 == arrData[i], "Writer " << nWriter << ": [" << (i-1) << "]=" << arrData[i-1] << ", [" << i << "]=" << arrData[i] ); - if ( ++nErrors > 10 ) - return; - } - } - - CPPUNIT_CHECK_EX( arrData[0] == 0, "Writer " << nWriter << "[0] != 0" ); - CPPUNIT_CHECK_EX( arrData[arrData.size() - 1] == m_nThreadPushCount - 1, "Writer " << nWriter << "[last] != " << m_nThreadPushCount - 1 ); - } - } - - template - void test() - { - m_nThreadPushCount = s_nQueueSize / s_nWriterThreadCount; - CPPUNIT_MSG( " reader count=" << s_nReaderThreadCount << " writer count=" << s_nWriterThreadCount - << " item count=" << m_nThreadPushCount * s_nWriterThreadCount << "..." ); - - Queue testQueue; - CppUnitMini::ThreadPool pool( *this ); - - m_nWriterDone.store( 0 ); - - // Writers must be first - pool.add( new WriterThread( pool, testQueue ), s_nWriterThreadCount ); - pool.add( new ReaderThread( pool, testQueue ), s_nReaderThreadCount ); - - //CPPUNIT_MSG( " Reader/Writer test, reader count=" << s_nReaderThreadCount << " writer count=" << s_nWriterThreadCount << "..." ); - pool.run(); - - analyze( pool, testQueue ); - CPPUNIT_MSG( testQueue.statistics() ); - } - - template - void test_segmented() - { - m_nThreadPushCount = s_nQueueSize / s_nWriterThreadCount; - CPPUNIT_MSG( " reader count=" << s_nReaderThreadCount << " writer count=" << s_nWriterThreadCount - << " item count=" << m_nThreadPushCount * s_nWriterThreadCount << "..." ); - - for ( size_t nSegmentSize = 4; nSegmentSize <= 256; nSegmentSize *= 4 ) { - CPPUNIT_MSG( "Segment size: " << nSegmentSize ); - - Queue q( nSegmentSize ); - CppUnitMini::ThreadPool pool( *this ); - - m_nWriterDone.store( 0 ); - - // Writers must be first - pool.add( new WriterThread( pool, q ), s_nWriterThreadCount ); - pool.add( new ReaderThread( pool, q ), s_nReaderThreadCount ); - - pool.run(); - - analyze( pool, q, nSegmentSize * 2, nSegmentSize ); - CPPUNIT_MSG( q.statistics() ); - } - } - - void setUpParams( const CppUnitMini::TestCfg& cfg ) { - s_nReaderThreadCount = cfg.getULong("ReaderCount", 4 ); - s_nWriterThreadCount = cfg.getULong("WriterCount", 4 ); - s_nQueueSize = cfg.getULong("QueueSize", 10000000 ); - } - - protected: - CDSUNIT_DECLARE_MoirQueue( Value ) - CDSUNIT_DECLARE_MSQueue( Value ) - CDSUNIT_DECLARE_OptimisticQueue( Value ) - CDSUNIT_DECLARE_BasketQueue( Value ) - CDSUNIT_DECLARE_FCQueue( Value ) - CDSUNIT_DECLARE_FCDeque( Value ) - CDSUNIT_DECLARE_SegmentedQueue( Value ) - CDSUNIT_DECLARE_RWQueue( Value ) - CDSUNIT_DECLARE_TsigasCycleQueue( Value ) - CDSUNIT_DECLARE_VyukovMPMCCycleQueue( Value ) - CDSUNIT_DECLARE_StdQueue( Value ) - - CPPUNIT_TEST_SUITE(Queue_ReaderWriter) - CDSUNIT_TEST_MoirQueue - CDSUNIT_TEST_MSQueue - CDSUNIT_TEST_OptimisticQueue - CDSUNIT_TEST_BasketQueue - CDSUNIT_TEST_FCQueue - CDSUNIT_TEST_FCDeque - CDSUNIT_TEST_SegmentedQueue - CDSUNIT_TEST_RWQueue - CDSUNIT_TEST_TsigasCycleQueue - CDSUNIT_TEST_VyukovMPMCCycleQueue - CDSUNIT_TEST_StdQueue - CPPUNIT_TEST_SUITE_END(); - }; - -} // namespace queue - -CPPUNIT_TEST_SUITE_REGISTRATION(queue::Queue_ReaderWriter); -- 2.34.1