├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── Doxyfile.in ├── README.md ├── benchmarks ├── 0initial.svg ├── 1after_imp_benchmark.svg ├── 2after_imp_v_iface.svg ├── CMakeLists.txt ├── access_patterns.hpp ├── benchmark.cpp ├── benchmark.hpp ├── benchmark.py ├── cartesian_product.hpp ├── dummy.png ├── dummy.svg ├── initializers.hpp ├── is_fusion_pair.hpp ├── is_scattered.hpp ├── operations.hpp ├── res.png ├── res.svg ├── scattered_vector_large_object_multiply_by_itself_one_sequential.dat ├── scattered_vector_medium_object_multiply_by_itself_one_sequential.dat ├── scattered_vector_small_object_multiply_by_itself_one_sequential.dat ├── scattered_vector_very_small_object_multiply_by_itself_one_sequential.dat ├── size_sequences.hpp ├── std_vector_large_object_multiply_by_itself_one_sequential.dat ├── std_vector_medium_object_multiply_by_itself_one_sequential.dat ├── std_vector_small_object_multiply_by_itself_one_sequential.dat ├── std_vector_very_small_object_multiply_by_itself_one_sequential.dat ├── template.gp ├── tests.hpp ├── time_function.hpp ├── types.hpp ├── vector_benchmark └── vector_benchmark.cpp ├── cmake └── FindLIBCXX.cmake ├── configure.sh ├── docs └── img │ └── memory_layout.svg ├── ext └── catch │ └── CMakeLists.txt ├── scattered ├── detail │ ├── as_fusion_map.hpp │ ├── assert.hpp │ ├── container_traits.hpp │ ├── fusion_swap.hpp │ ├── get.hpp │ ├── map.hpp │ ├── map_mutation.hpp │ ├── pair.hpp │ ├── returns.hpp │ ├── type_list.hpp │ ├── unqualified.hpp │ ├── vector.hpp │ └── vector_iterator_base.hpp └── vector.hpp ├── tests ├── CMakeLists.txt ├── example_test.cpp ├── map_test.cpp ├── pair_test.cpp ├── test_types.hpp └── vector_test.cpp └── tools ├── check_format.sh ├── cleanup.sh └── update_format.sh /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 2 3 | AccessModifierOffset: -1 4 | AlignEscapedNewlinesLeft: true 5 | AlignTrailingComments: true 6 | AllowAllParametersOfDeclarationOnNextLine: false 7 | AllowShortIfStatementsOnASingleLine: true 8 | AllowShortLoopsOnASingleLine: true 9 | AlwaysBreakBeforeMultilineStrings: false 10 | AlwaysBreakTemplateDeclarations: false 11 | BinPackParameters: true 12 | BreakBeforeBinaryOperators: true 13 | BreakBeforeBraces: Attach 14 | BreakConstructorInitializersBeforeComma: true 15 | ColumnLimit: 80 16 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 17 | ConstructorInitializerIndentWidth: 2 18 | Cpp11BracedListStyle: true 19 | IndentCaseLabels: true 20 | MaxEmptyLinesToKeep: 1 21 | NamespaceIndentation: None 22 | PointerBindsToType: true 23 | SpaceAfterControlStatementKeyword: true 24 | SpaceBeforeAssignmentOperators: true 25 | SpaceInEmptyParentheses: false 26 | SpacesBeforeTrailingComments: 2 27 | SpacesInCStyleCastParentheses: true 28 | SpacesInParentheses: false 29 | SpacesInAngles: false 30 | Standard: Cpp11 31 | TabWidth: 2 32 | UseTab: Never 33 | DerivePointerBinding: false 34 | IndentFunctionDeclarationAfterType: false 35 | ContinuationIndentWidth: 4 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | *.dylib 9 | 10 | # Compiled Static libraries 11 | *.lai 12 | *.la 13 | *.a 14 | 15 | # CMake files 16 | CMakeCache.txt 17 | CMakeFiles 18 | Makefile 19 | cmake_install.cmake 20 | install_manifest.txt 21 | 22 | # CTest files 23 | CTestTestfile.cmake 24 | Testing 25 | 26 | # VTK files 27 | *.vtk 28 | 29 | # Doxygen 30 | Doxyfile 31 | 32 | # Backup files (e.g. from emacs) 33 | *~ 34 | .#* -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project(ScatteredContainers) 3 | 4 | # Module path 5 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 6 | set(COMMON_INCLUDES ${PROJECT_SOURCE_DIR}) 7 | set(EXT_PROJECTS_DIR ${PROJECT_SOURCE_DIR}/ext) 8 | 9 | # Environment 10 | set(CMAKE_OSX_SYSROOT $ENV{SDKROOT}) 11 | 12 | # Configure compiler: 13 | message("Build type: ${CMAKE_BUILD_TYPE}") 14 | message("The compiler is: ${CMAKE_CXX_COMPILER}") 15 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") 16 | 17 | # libcxx: 18 | include_directories(SYSTEM ${LIBCXX_INCLUDE_DIR}) 19 | message("libcxx_include: ${LIBCXX_INCLUDE_DIR} | libcxx_lib: ${LIBCXX_LIBRARY}") 20 | set(CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} -L${LIBCXX_LIBRARY} -lc++") 21 | message("linker flags: ${CMAKE_EXE_LINKER_FLAGS}") 22 | 23 | # compiler flags: 24 | set(CMAKE_CXX_FLAGS_LIST 25 | "-arch x86_64" "-Wall" "-Wextra" "-std=c++1y" "-stdlib=libc++" 26 | "-pedantic" "-Wshadow" "-Woverloaded-virtual" 27 | "-pedantic-errors" "-Wcast-align" "-Wcomment" "-Wcast-qual" 28 | "-Wchar-subscripts" "-Wdisabled-optimization" "-Wfloat-equal" "-Wformat=2" 29 | "-Winvalid-pch" "-Wformat-nonliteral" "-Wformat-security" "-Wformat-y2k" 30 | "-Wimport" "-Winit-self" "-Winline" "-Wreturn-type" "-Wmissing-braces" 31 | "-Wmissing-field-initializers" "-Wmissing-include-dirs" "-Wredundant-decls" 32 | "-Wpacked" "-Wparentheses" "-Wpointer-arith" "-Wsequence-point" 33 | "-Wsign-compare" "-Wstack-protector" "-Wstrict-aliasing=2" "-Wswitch" 34 | "-Wswitch-default" "-Wtrigraphs" "-Wuninitialized" "-Wunknown-pragmas" 35 | "-Wunreachable-code" "-Wunused" "-Wunused-function" "-Wunused-label" 36 | "-Wunused-parameter" "-Wunused-value" "-Wunused-variable" 37 | "-Wvariadic-macros" "-Wvolatile-register-var" "-Wwrite-strings" 38 | "-Woverloaded-virtual" "-Wsign-promo" "-Wstrict-overflow=5" 39 | "-Wswitch-default" "-DGTEST_USE_OWN_TR1_TUPLE=1" 40 | "-fdiagnostics-show-template-tree" "-ftemplate-backtrace-limit=0" 41 | "-Wno-attributes" "-DFUSION_MAX_MAP_SIZE=40" "-DFUSION_MAX_VECTOR_SIZE=40" 42 | ) 43 | set(CMAKE_CXX_FLAGS_DEBUG_LIST 44 | "-O1" "-g3" "-fstack-protector-all" 45 | "-fsanitize=address" "-fno-omit-frame-pointer" 46 | ) # -D_LIBCPP_DEBUG2=1 47 | set(CMAKE_CXX_FLAGS_RELEASE_LIST 48 | "-O3" "-DNDEBUG" "-march=native" "-mtune=native" "-fstrict-aliasing" 49 | "-fomit-frame-pointer" "-pipe" "-fdata-sections" "-ffunction-sections" 50 | "-fvectorize" "-fslp-vectorize-aggressive" "-DEIGEN_FAST_MATH" 51 | "-DEIGEN_NO_DEBUG" "-ffast-math" 52 | ) # -fno-rtti -fno-exceptions 53 | set(CMAKE_CXX_FLAGS_ASAN_LIST 54 | ${CMAKE_CXX_FLAGS_RELEASE_LIST} 55 | "-fsanitize=address" "-fno-omit-frame-pointer" 56 | ) 57 | set(CMAKE_CXX_FLAGS_MSAN_LIST 58 | ${CMAKE_CXX_FLAGS_RELEASE_LIST} 59 | "-fsanitize=memory" "-fno-omit-frame-pointer" 60 | "-fsanitize-memory-track-origins" 61 | ) 62 | set(CMAKE_CXX_FLAGS_TSAN_LIST 63 | ${CMAKE_CXX_FLAGS_RELEASE_LIST} 64 | "-fsanitize=thread" "-fno-omit-frame-pointer" 65 | "-fsanitize-memory-track-origins" 66 | ) 67 | 68 | # set flags: 69 | string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_LIST}") 70 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG_LIST}") 71 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE_LIST}") 72 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_ASAN_LIST}") 73 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_MSAN "${CMAKE_CXX_FLAGS_MSAN_LIST}") 74 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_TSAN "${CMAKE_CXX_FLAGS_TSAN_LIST}") 75 | 76 | # output flags: 77 | message("...clang flags set: " ${CMAKE_CXX_FLAGS}) 78 | if("${CMAKE_BUILD_TYPE}" MATCHES "Debug") 79 | message("...clang optimization flags set: ${CMAKE_CXX_FLAGS_DEBUG}") 80 | elseif("${CMAKE_BUILD_TYPE}" MATCHES "Release") 81 | message("...clang optimization flags set: ${CMAKE_CXX_FLAGS_RELEASE}") 82 | elseif("${CMAKE_BUILD_TYPE}" MATCHES "Asan") 83 | message("...clang optimization flags set: ${CMAKE_CXX_FLAGS_ASAN}") 84 | set(CMAKE_EXE_LINKER_FLAGS " ${CMAKE_EXE_LINKER_FLAGS} -L${LIBCXX_LIBRARY} -lc++") 85 | elseif("${CMAKE_BUILD_TYPE}" MATCHES "Msan") 86 | message("...clang optimization flags set: ${CMAKE_CXX_FLAGS_MSAN}") 87 | elseif("${CMAKE_BUILD_TYPE}" MATCHES "Tsan") 88 | message("...clang optimization flags set: ${CMAKE_CXX_FLAGS_TSAN}") 89 | else() 90 | message(FATAL_ERROR "Unknown build type. Options are \"Debug\" and \"Release\". Quit.") 91 | endif() 92 | message("...linker flags set: ${CMAKE_EXE_LINKER_FLAGS}") 93 | else() 94 | message(FATAL_ERROR "Unknown compiler, quit.") 95 | endif() 96 | 97 | # boost 98 | #set(Boost_USE_STATIC_LIBS OFF) 99 | #set(Boost_USE_MULTITHREADED ON) 100 | #set(Boost_USE_STATIC_RUNTIME ON) 101 | #find_package(Boost 1.55 REQUIRED) 102 | #include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) 103 | include_directories(SYSTEM ${BOOST_DIRS}) 104 | include_directories(SYSTEM ./) 105 | 106 | # Catch (and enables unit testing) 107 | add_subdirectory(${EXT_PROJECTS_DIR}/catch) 108 | include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES}) 109 | enable_testing(true) 110 | 111 | set(TESTING_INCLUDES ${CATCH_INCLUDE_DIR} ) 112 | function(add_scattered_test name) 113 | include_directories(${TESTING_INCLUDES} ${COMMON_INCLUDES}) 114 | add_executable(${name}_test ${name}_test.cpp) 115 | add_test(${name}_test ${name}_test) 116 | endfunction(add_scattered_test) 117 | 118 | function(add_benchmark name) 119 | include_directories(${TESTING_INCLUDES} ${COMMON_INCLUDES}) 120 | add_executable(${name}_benchmark ${name}_benchmark.cpp) 121 | add_test(${name}_benchmark ${name}_benchmark) 122 | endfunction(add_benchmark) 123 | 124 | # Doxygen (optional) - Enables "make docs" 125 | option(BUILD_DOCUMENTATION "Use Doxygen to create the HTML documentation" ON) 126 | if(BUILD_DOCUMENTATION) 127 | find_package(Doxygen) 128 | if (NOT DOXYGEN_FOUND) 129 | message(FATAL_ERROR "Doxygen can't be found.") 130 | endif() 131 | configure_file(Doxyfile.in ${PROJECT_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE) 132 | add_custom_target (docs 133 | ${DOXYGEN_EXECUTABLE} 134 | ${PROJECT_BINARY_DIR}/Doxyfile 135 | SOURCES 136 | ${PROJECT_BINARY_DIR}/Doxyfile) 137 | endif() 138 | 139 | # Clean-up - enables "make clean" 140 | set(CLEANUP_SCRIPT ${PROJECT_BINARY_DIR}/tools/cleanup.sh) 141 | add_custom_target (clean ${CLEANUP_SCRIPT}) 142 | 143 | # Subdirectories: 144 | add_subdirectory (./tests) 145 | add_subdirectory (./benchmarks) 146 | 147 | # Clang format 148 | file(GLOB_RECURSE files *.hpp *.cpp) 149 | add_custom_command(OUTPUT formatting COMMAND 150 | ${CMAKE_CURRENT_SOURCE_DIR}/tools/check_format.sh ${files}) 151 | add_custom_target(check-format DEPENDS formatting) 152 | add_custom_command(OUTPUT formatting-update COMMAND 153 | ${CMAKE_CURRENT_SOURCE_DIR}/tools/update_format.sh ${files}) 154 | add_custom_target(update-format DEPENDS formatting-update) 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### Introduction 2 | 3 | Scattered container store each type's data member sequentially for all 4 | objects. That is, the first data member of all objects is stored contiguosly in 5 | memory, then the second data member, and so on as shown in the following figure: 6 | 7 | ![Memory layout of standard and scattered 8 | containers](https://rawgithub.com/gnzlbg/scattered/master/docs/img/memory_layout.svg 9 | "Memory layout of standard and scattered containers for a type containing an 10 | int, a bool, and a double as data members.") 11 | 12 | This improves cache line utilization when iterating sequentially over a 13 | container without accessing all object's data members. They also allow 14 | asynchronous processing of object's data member without false sharing. 15 | 16 | The following containers are available: 17 | - `scattered::vector` (analogous to `std::vector`). 18 | 19 | Scattered is a [Boost Software License](http://www.boost.org/LICENSE_1_0.txt)'d 20 | header only C++1y library and is tested with Boost 1.54 (1.55 not supported yet, 21 | see issue tracker) and trunk clang/libc++. It depends on [Boost.MPL]() and 22 | [Boost.Fusion](). 23 | 24 | ##### Example: `scattered::vector` 25 | 26 | ```c++ 27 | #include 28 | #include 29 | #include 30 | #include "scattered/vector.hpp" 31 | 32 | /// T is a struct; k contains keys to access the struct elements: 33 | struct T { 34 | float x; double y; int i; bool b; 35 | struct k { struct x {}; struct y {}; struct i {}; struct b {}; }; 36 | }; 37 | 38 | /// This adapts the class as an associative fusion sequence 39 | BOOST_FUSION_ADAPT_ASSOC_STRUCT( 40 | T, (float, x, T::k::x)(double, y, T::k::y) 41 | (int , i, T::k::i)(bool , b, T::k::b)) 42 | 43 | int main() { 44 | using scattered::get; 45 | using k = T::k; 46 | 47 | scattered::vector vec(10); 48 | 49 | /// To modify the elements of the vector in place 50 | /// the keys are used on a reference proxy: 51 | int count = 0; 52 | for (auto i : vec) { 53 | get(i) = static_cast(count); 54 | get(i) = static_cast(count); 55 | get(i) = count; 56 | get(i) = count % 2 == 0; 57 | ++count; 58 | } 59 | 60 | /// Cache lines contain only "y" data-members: 61 | for (auto i : vec) { get(i) += get(i); } 62 | 63 | /// Boost and STL algorithms work out of the box 64 | boost::stable_sort(vec, [](auto i, auto j) { 65 | return get(i) > get(j); 66 | }); 67 | 68 | /// Reference proxy implicitly converts to T 69 | boost::transform(vec, std::begin(vec), [](T i) { i.y *= i.y; return i; }); 70 | vec.push_back(T{4.0, 3.0, 2, false}); 71 | } 72 | ``` 73 | 74 | #### Getting started 75 | - `./configure.sh` is used to provide libc++'s path and select the compilation 76 | mode (debug/release/sanitizers are provided, see `./configure,sh -h`). 77 | - `make` compiles the tests, `ctest` launches all tests. 78 | - `make docs` builds the documentation. 79 | - `make update-format` reformats the code with clang-format. 80 | - `make bench` runs all benchmarks. 81 | 82 | ##### Caveats 83 | 84 | Scattered containers use proxy reference types and, as a consequence, have the 85 | following caveats similar to those of `std::vector`: 86 | 87 | ```c++ 88 | // i's type = scattered::vector::reference, not scattered::vector::value_type 89 | auto i = *scatteredVector.begin(); 90 | 91 | // j's type = scattered::vector::reference& 92 | auto& j = *scatteredVector.begin(); 93 | 94 | // this modifies scatteredVector: 95 | i = T{}; 96 | 97 | // to get a value you need to use value_type (or T) 98 | T value = *scatteredVector.begin(); 99 | 100 | // This fails because T& cannot bind to scattered::vector::reference& 101 | T& ref = *catteredVector.begin(); // Compilation Error 102 | ``` 103 | 104 | ##### Main idea behind implementation 105 | 106 | Scattered relies on 107 | [BOOST_FUSION_ADAPT_ASSOC_X](http://www.boost.org/doc/libs/1_55_0/libs/fusion/doc/html/fusion/adapted.html) 108 | to adapt classes as associative Boost.Fusion sequences. The 109 | `scattered::get(reference_proxy)` function returns a reference to the 110 | object's data member associated with the `key`. 111 | 112 | #### Benchmarks 113 | 114 | The aim of the library is to maximize memory bandwidth usage for algorithms that 115 | iterate *sequentially* over the container. The following benchmarks are located 116 | in the `benchmarks/` directory and can be run with `make bench`. 117 | 118 | #### Todo: 119 | 120 | See the [roadmaps](https://github.com/gnzlbg/scattered/issues) page in the issue 121 | list. 122 | 123 | - Finish: `scattered::vector` will be provided. 124 | - Other containers: `scattered::flat_set` and `scattered::unordered_map`. 125 | 126 | #### Acknowledgments 127 | 128 | The Scattered library resulted from efforts to improve the cache performance of 129 | numerical fluid mechanics codes at the Institute of Aerodynamics, Aachen. I'd 130 | like to thank Georg Geiser for introducing me to [What Every Programmer Should 131 | Know About 132 | Memory](http://people.freebsd.org/~lstewart/articles/cpumemory.pdf). Furthermore, 133 | I want to thank the guests of the 134 | [LoungeC++](http://chat.stackoverflow.com/rooms/10/loungec) for their 135 | discussions, company, and help. In particular, to Evgeny Panasyuk who motivated 136 | me to write this library. 137 | -------------------------------------------------------------------------------- /benchmarks/0initial.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 4.6 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 0.5 42 | 43 | 44 | 1 45 | 46 | 47 | 1.5 48 | 49 | 50 | 2 51 | 52 | 53 | 2.5 54 | 55 | 56 | 3 57 | 58 | 59 | 0.1 60 | 61 | 64 | 1 65 | 66 | 69 | 10 70 | 71 | 74 | 100 75 | 76 | 79 | 1000 80 | 81 | 84 | 10000 85 | 86 | 89 | 100000 90 | 91 | 94 | 1e+06 95 | 96 | 99 | 1e+07 100 | 101 | 102 | Speed-up w.r.t. std::vector [-] 103 | 104 | 105 | #of iterations [-] 106 | 107 | 108 | Accessing one data member 109 | 110 | 111 | gnuplot_plot_1 112 | 113 | 114 | verysmall 115 | 116 | 117 | 118 | gnuplot_plot_2 119 | 120 | 121 | small 122 | 123 | 124 | 125 | gnuplot_plot_3 126 | 127 | 128 | medium 129 | 130 | 131 | 132 | gnuplot_plot_4 133 | 134 | 135 | large 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /benchmarks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_benchmark(vector) 2 | -------------------------------------------------------------------------------- /benchmarks/access_patterns.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2013 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_ACCESS_PATTERNS_HPP) 7 | #define SCATTERED_BENCHMARK_ACCESS_PATTERNS_HPP 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | struct sequential { 12 | template 13 | [[gnu::flatten, gnu::hot]] inline void operator()(C&& container, F&& operation) const { 14 | for (auto&& i : container) { 15 | operation(i); 16 | } 17 | } 18 | }; 19 | 20 | auto name(sequential) RETURNS(std::string{"sequential"}); 21 | 22 | //////////////////////////////////////////////////////////////////////////////// 23 | 24 | template struct strided { 25 | template 26 | [[gnu::flatten, gnu::hot]] inline void operator()(C&& container, F&& operation) const { 27 | for (std::size_t i = 0, e = container.size(); i < e; i += stride) { 28 | operation(container[i]); 29 | } 30 | } 31 | }; 32 | 33 | template 34 | auto name(strided) RETURNS("strided_" + std::to_string(stride)); 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | using access_patterns = boost::mpl::vector 40 | // , strided<4> 41 | >; 42 | 43 | #endif // SCATTERED_BENCHMARK_ACCESS_PATTERNS_HPP 44 | -------------------------------------------------------------------------------- /benchmarks/benchmark.cpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #include "benchmark.hpp" 7 | 8 | int main() { 9 | 10 | // for each container: 11 | // for each operation: 12 | // for each access pattern: 13 | // for each type: 14 | // write benchmark name 15 | // for each size: 16 | // create benchmark 17 | // run benchmark 18 | // write timings 19 | // 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /benchmarks/benchmark.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_BENCHMARK_HPP) 7 | #define SCATTERED_BENCHMARK_BENCHMARK_HPP 8 | 9 | #include 10 | #include 11 | #include "time_function.hpp" 12 | 13 | template 18 | struct Benchmark { 19 | Benchmark() {} 20 | Benchmark(std::size_t size) : c(size) { 21 | Initializer{}(c); 22 | } 23 | auto operator()() { 24 | return time_fn([&]() { AccessPattern{}(c, Operation{}); }); 25 | } 26 | Container c; 27 | }; 28 | 29 | template 31 | auto name(Benchmark) { 33 | using std::setw; using std::left; 34 | auto n = std::string{"Benchmark: "} + name(Container{}) + "<" + name(Type{}) + ">"; 35 | auto op = std::string{"op: "} + name(Operation{}); 36 | auto ap = std::string{"ap: "} + name(AccessPattern{}); 37 | std::stringstream ss; 38 | ss << setw(50) << left << n; 39 | ss << setw(50) << left << op; 40 | ss << setw(50) << left << ap << "\n"; 41 | return ss.str(); 42 | } 43 | 44 | template 46 | auto fname(Benchmark) { 48 | 49 | return name(Container{}) + std::string{"_"} + name(Type{}) + "_" 50 | + name(Operation{}) + "_" + name(AccessPattern{}); 51 | } 52 | 53 | #endif // SCATTERED_BENCHMARK_BENCHMARK_HPP 54 | -------------------------------------------------------------------------------- /benchmarks/benchmark.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | -------------------------------------------------------------------------------- /benchmarks/cartesian_product.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_MPL_CARTESIAN_PRODUCT_HPP_INCLUDED 2 | #define BOOST_MPL_CARTESIAN_PRODUCT_HPP_INCLUDED 3 | 4 | // Based on boost::mpl::for_each.hpp, 5 | // Copyright Aleksey Gurtovoy 2000-2008 6 | //------------------------------------------------------------ 7 | // This file Copyright George van Venrooij 2008 8 | // http://www.organicvectory.com 9 | // 10 | // Distributed under the Boost Software License, Version 1.0. 11 | // (See http://www.boost.org/LICENSE_1_0.txt) 12 | // 13 | // Documentation: 14 | // 15 | // cartesian_product is a run-time algorithm that works on a 16 | // sequence of sequences. 17 | // 18 | // While executing, it constructs a mpl::vector containing 19 | // one element of each of the sequences and it does so until 20 | // it exhausts all possible combinations. 21 | // 22 | // See http://en.wikipedia.org/wiki/Cartesian_product for 23 | // the official specification. 24 | // 25 | // For example: 26 | // 27 | // typedef boost::mpl::vector t1; 28 | // typedef boost::mpl::vector t2; 29 | // typedef boost::mpl::vector t3; 30 | // 31 | // typedef boost::mpl::vector tt; 32 | // 33 | // template 34 | // void F() 35 | // { 36 | // } 37 | // 38 | // cartesian_product(F); 39 | // 40 | // 41 | // F() is called for the following types: 42 | // 43 | // boost::mpl::vector 44 | // boost::mpl::vector 45 | // 46 | // boost::mpl::vector 47 | // boost::mpl::vector 48 | // 49 | // boost::mpl::vector 50 | // boost::mpl::vector 51 | // 52 | // boost::mpl::vector 53 | // boost::mpl::vector 54 | // 55 | // 56 | // Intended use 57 | // ------------ 58 | // 59 | // This design evolved out of another design where the behavior of software system was specified 60 | // using various type sequences. A generic implementation needed to be overloaded for specific 61 | // combinations of types and the search for a way to do that indicated the need for such an 62 | // algorithm. 63 | // 64 | // Another use for the algorithm was in testing a complex class where specific functionality of 65 | // that class could be specified in external functors that are then passed as type parameters to 66 | // the class template. 67 | // 68 | // Using cartesian_product is an easy way to test various configurations in a common manner. 69 | // 70 | // A short piece of code demonstrates this: 71 | // 72 | // template 73 | // class complex_class 74 | // { 75 | // }; 76 | // 77 | // // Test function that creates a complex class from a type sequence and then tests it 78 | // template 79 | // void 80 | // test_complex_class() 81 | // { 82 | // typedef complex_class 83 | // < at::type 84 | // , at::type 85 | // , at::type 86 | // > test_class_t; 87 | // 88 | // test_class_t my_class; 89 | // 90 | // // Perform some tests on my_class 91 | // } 92 | // 93 | // // Variants of the template parameters 94 | // typedef boost::mpl::vector T1Variants; 95 | // typedef boost::mpl::vector T2Variants; 96 | // typedef boost::mpl::vector T3Variants; 97 | // 98 | // // Combined sequence 99 | // typedef boost::mpl::vector TT; 100 | // 101 | // test() 102 | // { 103 | // boost::mpl::cartesian_product(test_complex_class); 104 | // } 105 | 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | 113 | #include 114 | 115 | namespace boost 116 | { 117 | namespace mpl 118 | { 119 | namespace aux 120 | { 121 | // Stop condition for the recursion If done == true, then the end 122 | // of the sequence has been reached and nothing needs to be done 123 | template 124 | struct cartesian_product_inner_impl 125 | { 126 | template 127 | < typename CurrentType 128 | , typename LastType 129 | , typename CurrentSequence 130 | , typename LastSequence 131 | , typename ArgumentSequence // Sequence under construction 132 | , typename F 133 | > 134 | static void execute 135 | ( CurrentType* 136 | , LastType* 137 | , CurrentSequence* 138 | , LastSequence* 139 | , ArgumentSequence* 140 | , F 141 | ) 142 | { 143 | } 144 | }; 145 | 146 | template 147 | struct cartesian_product_outer_impl; 148 | 149 | // The specialization takes care of the case where the recursion is NOT yet done 150 | template<> 151 | struct cartesian_product_inner_impl 152 | { 153 | template 154 | < typename CurrentType // Iterator to current type in sequence 155 | , typename LastType // Iterator to last/end type in sequence 156 | , typename CurrentSequence // Iterator to current outer sequence 157 | , typename LastSequence // Iterator to last/end outer seuqence 158 | , typename ArgumentSequence // Sequence under construction 159 | , typename F // Functor to call 160 | > 161 | static void execute 162 | ( CurrentType* 163 | , LastType* 164 | , CurrentSequence* 165 | , LastSequence* 166 | , ArgumentSequence* 167 | , F f 168 | ) 169 | { 170 | // Retrieve the type from the sequence 171 | typedef typename deref::type item; 172 | 173 | // Add it to the argument sequence 174 | typedef typename push_back::type NewSequence; 175 | 176 | // Step to next element in the sequence 177 | typedef typename mpl::next::type NextType; 178 | 179 | // Start working on the next sequence 180 | cartesian_product_outer_impl 181 | < boost::is_same::value 182 | >::execute 183 | ( (CurrentSequence*) 0 184 | , (LastSequence*) 0 185 | , (NewSequence*) 0 186 | , f 187 | ); 188 | 189 | // Continue with next element of current sequence 190 | cartesian_product_inner_impl 191 | < boost::is_same::value 192 | >::execute 193 | ( (NextType*) 0 194 | , (LastType*) 0 195 | , (CurrentSequence*) 0 196 | , (LastSequence*) 0 197 | , (ArgumentSequence*) 0 198 | , f 199 | ); 200 | } 201 | }; 202 | 203 | // Stop condition for the recursion 204 | // If done == true, then the end of the sequence has been reached and nothing needs to be done 205 | template 206 | struct cartesian_product_outer_impl 207 | { 208 | template 209 | < typename CurrentSequence 210 | , typename LastSequence 211 | , typename ArgumentSequence 212 | , typename F 213 | > 214 | static void execute 215 | ( CurrentSequence* 216 | , LastSequence* 217 | , ArgumentSequence* 218 | , F f 219 | ) 220 | { 221 | value_initialized x; 222 | aux::unwrap(f, 0)(boost::get(x)); 223 | } 224 | }; 225 | 226 | // The specialization takes care of the case where the recursion is NOT yet done 227 | // 228 | // This is called for every outer sequence 229 | template<> 230 | struct cartesian_product_outer_impl 231 | { 232 | template 233 | < typename CurrentSequence // Iterator to current outer sequence 234 | , typename LastSequence // Iterator to last outer sequence 235 | , typename ArgumentSequence // Sequence under construction 236 | , typename F // Functor 237 | > 238 | static void execute 239 | ( CurrentSequence* 240 | , LastSequence* 241 | , ArgumentSequence* 242 | , F f 243 | ) 244 | { 245 | // Retrieve the inner sequence from the current outer sequence 246 | typedef typename deref::type InnerSequence; 247 | 248 | // Check if the inner sequence passed into this call is actually a sequence 249 | BOOST_MPL_ASSERT(( is_sequence )); 250 | 251 | // Step to next element in the sequence 252 | typedef typename mpl::next::type NextSequence; 253 | 254 | // Inner sequence iterators 255 | typedef typename begin::type FirstType; 256 | typedef typename end ::type LastType; 257 | 258 | // Process inner sequence types 259 | cartesian_product_inner_impl 260 | < boost::is_same::value 261 | >::execute 262 | ( (FirstType*) 0 263 | , (LastType*) 0 264 | , (NextSequence*) 0 265 | , (LastSequence*) 0 266 | , (ArgumentSequence*) 0 267 | , f 268 | ); 269 | } 270 | }; 271 | 272 | } // namespace aux 273 | 274 | // The cartesian_product algorithm 275 | template 276 | < typename SequenceOfSequences 277 | , typename F 278 | > 279 | inline 280 | void cartesian_product 281 | ( F f 282 | , SequenceOfSequences* = 0 283 | ) 284 | { 285 | // Check if the sequence passed into this call is actually a sequence 286 | BOOST_MPL_ASSERT(( is_sequence )); 287 | 288 | // Get iterators to start and end of sequence 289 | typedef typename begin::type FirstSequence; 290 | typedef typename end ::type LastSequence; 291 | 292 | // Use recursion to iterate over all outer sequence elements 293 | // The recursion stops as soon first == last 294 | aux::cartesian_product_outer_impl 295 | < boost::is_same::value 296 | >::execute 297 | ( (FirstSequence*)0 298 | , (LastSequence*) 0 299 | , (vector0<>*) 0 300 | , f 301 | ); 302 | } 303 | 304 | } // namespace mpl 305 | } // namespace boost 306 | #endif // BOOST_MPL_CARTESIAN_PRODUCT_HPP_INCLUDED 307 | -------------------------------------------------------------------------------- /benchmarks/dummy.png: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | Gnuplot 12 | Produced by GNUPLOT 4.6 patchlevel 3 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 40 | 41 | 0.5 42 | 43 | 44 | 1 45 | 46 | 47 | 1.5 48 | 49 | 50 | 2 51 | 52 | 53 | 2.5 54 | 55 | 56 | 3 57 | 58 | 59 | 0.1 60 | 61 | 64 | 1 65 | 66 | 69 | 10 70 | 71 | 74 | 100 75 | 76 | 79 | 1000 80 | 81 | 84 | 10000 85 | 86 | 89 | 100000 90 | 91 | 94 | 1e+06 95 | 96 | 99 | 1e+07 100 | 101 | 102 | Speed-up w.r.t. std::vector [-] 103 | 104 | 105 | #of iterations [-] 106 | 107 | 108 | Accessing one data member 109 | 110 | 111 | gnuplot_plot_1 112 | 113 | 114 | verysmall 115 | 116 | 117 | 118 | gnuplot_plot_2 119 | 120 | 121 | small 122 | 123 | 124 | 125 | gnuplot_plot_3 126 | 127 | 128 | medium 129 | 130 | 131 | 132 | gnuplot_plot_4 133 | 134 | 135 | large 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /benchmarks/dummy.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnzlbg/scattered/a9eaf8558136bcb64ceb02c0277dd4d767e8e9ae/benchmarks/dummy.svg -------------------------------------------------------------------------------- /benchmarks/initializers.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_INITIALIZER_HPP) 7 | #define SCATTERED_BENCHMARK_INITIALIZER_HPP 8 | 9 | #include 10 | #include "scattered/detail/unqualified.hpp" 11 | #include "is_scattered.hpp" 12 | 13 | //////////////////////////////////////////////////////////////////////////////// 14 | 15 | struct fill_with_random_values { 16 | fill_with_random_values(int s = 1) { rng.seed(s); v = dist(rng); } 17 | using Engine = std::mt19937; 18 | using Dist = std::uniform_int_distribution; 19 | Engine rng; 20 | Dist dist; 21 | uint v; 22 | 23 | template 24 | enable_if_scattered operator()(C&& c) { 25 | for (auto&& i : c) { 26 | boost::fusion::for_each(i, [&](auto& o) { 27 | o.second = v; 28 | }); 29 | } 30 | } 31 | 32 | template 33 | disable_if_scattered operator()(C&& c) { 34 | for (auto&& i : c) { 35 | boost::fusion::for_each(i, [&](auto& o) { 36 | o = v; 37 | }); 38 | } 39 | } 40 | 41 | 42 | }; 43 | 44 | auto name(fill_with_random_values) 45 | RETURNS(std::string{"fill_with_random_values"}); 46 | 47 | //////////////////////////////////////////////////////////////////////////////// 48 | 49 | #endif // SCATTERED_BENCHMARK_INITIALIZER_HPP 50 | -------------------------------------------------------------------------------- /benchmarks/is_fusion_pair.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_IS_FUSION_PAIR_HPP) 7 | #define SCATTERED_BENCHMARK_IS_FUSION_PAIR_HPP 8 | 9 | #include "scattered/detail/unqualified.hpp" 10 | 11 | template struct is_fusion_pair_impl_ { 12 | static const bool value = false; 13 | }; 14 | 15 | template struct is_fusion_pair_impl_> { 16 | static const bool value = true; 17 | }; 18 | 19 | template struct is_fusion_pair { 20 | static const bool value = is_fusion_pair_impl_>::value; 21 | }; 22 | 23 | template using enable_if_fusion_pair = std::enable_if_t::value, void>; 24 | template using disable_if_fusion_pair = std::enable_if_t::value, void>; 25 | 26 | #endif // SCATTERED_BENCHMARK_IS_FUSION_PAIR_HPP 27 | -------------------------------------------------------------------------------- /benchmarks/is_scattered.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_IS_SCATTERED_HPP) 7 | #define SCATTERED_BENCHMARK_IS_SCATTERED_HPP 8 | 9 | #include "scattered/detail/unqualified.hpp" 10 | 11 | template class is_scattered { 12 | using T = scattered::detail::unqualified_t; 13 | 14 | template static auto test(C&&) -> decltype(typename C::scattered{}, std::true_type{}); 15 | template static auto test(...) -> std::false_type; 16 | 17 | public: 18 | using type = decltype(test(std::declval())); 19 | static const bool value = type::value; 20 | }; 21 | 22 | template using enable_if_scattered = std::enable_if_t::value, R>; 23 | template using disable_if_scattered = std::enable_if_t::value, R>; 24 | 25 | #endif // SCATTERED_BENCHMARK_IS_SCATTERED_HPP 26 | -------------------------------------------------------------------------------- /benchmarks/operations.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2013 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_OPERATIONS_HPP) 7 | #define SCATTERED_BENCHMARK_OPERATIONS_HPP 8 | 9 | #include "types.hpp" 10 | #include "is_fusion_pair.hpp" 11 | #include "is_scattered.hpp" 12 | #include "scattered/detail/unqualified.hpp" 13 | 14 | //////////////////////////////////////////////////////////////////////////////// 15 | 16 | struct multiply_by_itself_all { 17 | struct impl { 18 | template 19 | [[gnu::always_inline]] inline enable_if_fusion_pair operator()(T&& i) const { 20 | i.second *= i.second; 21 | } 22 | template 23 | [[gnu::always_inline]] inline disable_if_fusion_pair operator()(T&& i) const { 24 | i *= i; 25 | } 26 | }; 27 | 28 | template 29 | [[gnu::always_inline]] inline void operator()(T&& o) const { 30 | boost::fusion::for_each(o, impl{}); 31 | } 32 | }; 33 | 34 | auto name(multiply_by_itself_all) RETURNS(std::string{"multiply_by_itself_all"}); 35 | 36 | //////////////////////////////////////////////////////////////////////////////// 37 | 38 | struct multiply_by_itself_one { 39 | template 40 | [[gnu::always_inline]] inline disable_if_scattered operator()(T&& o) const { o.d0 *= o.d0; } 41 | template 42 | [[gnu::always_inline]] inline enable_if_scattered operator()(T&& o) const { 43 | scattered::get(o) *= scattered::get(o); 44 | } 45 | }; 46 | 47 | auto name(multiply_by_itself_one) RETURNS(std::string{"multiply_by_itself_one"}); 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | 51 | using operations = boost::mpl::vector< 52 | //multiply_by_itself_all, 53 | multiply_by_itself_one 54 | >; 55 | 56 | #endif // SCATTERED_BENCHMARK_OPERATIONS_HPP 57 | -------------------------------------------------------------------------------- /benchmarks/scattered_vector_large_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: scattered_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 20000000 250065906 4 | -------------------------------------------------------------------------------- /benchmarks/scattered_vector_medium_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: scattered_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 1 74 4 | 2 81 5 | 3 88 6 | 4 144 7 | 5 166 8 | 6 185 9 | 7 197 10 | 8 213 11 | 9 248 12 | 10 255 13 | 20 418 14 | 30 351 15 | 40 441 16 | 50 532 17 | 60 705 18 | 70 686 19 | 80 772 20 | 90 859 21 | 100 1034 22 | 200 1859 23 | 300 2916 24 | 400 3840 25 | 500 4763 26 | 600 5381 27 | 700 5845 28 | 800 6676 29 | 900 7356 30 | 1000 8179 31 | 2000 16543 32 | 3000 32205 33 | 4000 40751 34 | 5000 41935 35 | 6000 50811 36 | 7000 76851 37 | 8000 66231 38 | 9000 79958 39 | 10000 88787 40 | 20000 178765 41 | 30000 270545 42 | 40000 389615 43 | 50000 424598 44 | 60000 513977 45 | 70000 607845 46 | 80000 715440 47 | 90000 764178 48 | 100000 887523 49 | 200000 1679474 50 | 300000 3189694 51 | 400000 3361066 52 | 500000 4297426 53 | 600000 5258352 54 | 700000 6119939 55 | 800000 7049912 56 | 900000 8141032 57 | 1000000 9060345 58 | 2000000 18743876 59 | 3000000 28883769 60 | 4000000 37145781 61 | 5000000 50264718 62 | 6000000 55574289 63 | 7000000 78850447 64 | 8000000 77637836 65 | 9000000 80017813 66 | -------------------------------------------------------------------------------- /benchmarks/scattered_vector_small_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: scattered_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 20000000 60070583 4 | -------------------------------------------------------------------------------- /benchmarks/scattered_vector_very_small_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: scattered_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 1 44 4 | 2 42 5 | 3 50 6 | 4 48 7 | 5 37 8 | 6 40 9 | 7 42 10 | 8 66 11 | 9 68 12 | 10 57 13 | 20 99 14 | 30 134 15 | 40 147 16 | 50 189 17 | 60 210 18 | 70 223 19 | 80 283 20 | 90 312 21 | 100 336 22 | 200 515 23 | 300 740 24 | 400 953 25 | 500 1179 26 | 600 1404 27 | 700 1629 28 | 800 1858 29 | 900 2089 30 | 1000 2318 31 | 2000 4629 32 | 3000 6979 33 | 4000 8847 34 | 5000 12016 35 | 6000 13321 36 | 7000 14939 37 | 8000 17081 38 | 9000 20717 39 | 10000 23336 40 | 20000 49516 41 | 30000 79172 42 | 40000 93827 43 | 50000 120577 44 | 60000 143060 45 | 70000 154056 46 | 80000 178808 47 | 90000 214931 48 | 100000 254455 49 | 200000 454514 50 | 300000 701166 51 | 400000 933569 52 | 500000 1263362 53 | 600000 1720925 54 | 700000 2044550 55 | 800000 2078811 56 | 900000 2517172 57 | 1000000 2811669 58 | 2000000 4630581 59 | 3000000 6920079 60 | 4000000 9291348 61 | 5000000 11923999 62 | 6000000 13768156 63 | 7000000 17401448 64 | 8000000 18604693 65 | 9000000 21298552 66 | -------------------------------------------------------------------------------- /benchmarks/size_sequences.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_SIZE_SEQUENCES_HPP) 7 | #define SCATTERED_BENCHMARK_SIZE_SEQUENCES_HPP 8 | 9 | //////////////////////////////////////////////////////////////////////////////// 10 | 11 | auto log_sequence(std::size_t lower, std::size_t upper) { 12 | std::vector seq; 13 | seq.reserve(100); 14 | assert(lower > 0 && upper > 0 && upper > lower 15 | && "invalid range: lower < upper !"); 16 | while (lower < upper) { 17 | for (std::size_t i = 1; i < 10 && (i * lower) < upper; ++i) { 18 | seq.emplace_back(i * lower); 19 | } 20 | lower *= 10; 21 | } 22 | return seq; 23 | } 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | #endif // SCATTERED_BENCHMARK_SIZE_SEQUENCES_HPP 28 | -------------------------------------------------------------------------------- /benchmarks/std_vector_large_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: std_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 20000000 266571901 4 | -------------------------------------------------------------------------------- /benchmarks/std_vector_medium_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: std_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 1 27 4 | 2 28 5 | 3 29 6 | 4 31 7 | 5 31 8 | 6 32 9 | 7 32 10 | 8 33 11 | 9 34 12 | 10 35 13 | 20 41 14 | 30 53 15 | 40 68 16 | 50 74 17 | 60 85 18 | 70 90 19 | 80 99 20 | 90 102 21 | 100 112 22 | 200 189 23 | 300 692 24 | 400 1046 25 | 500 1281 26 | 600 1567 27 | 700 1801 28 | 800 2048 29 | 900 2271 30 | 1000 2519 31 | 2000 5020 32 | 3000 8422 33 | 4000 13243 34 | 5000 18490 35 | 6000 21639 36 | 7000 25965 37 | 8000 26626 38 | 9000 29339 39 | 10000 35295 40 | 20000 140759 41 | 30000 205337 42 | 40000 284978 43 | 50000 408827 44 | 60000 524849 45 | 70000 663262 46 | 80000 772091 47 | 90000 850292 48 | 100000 971583 49 | 200000 2169628 50 | 300000 3239783 51 | 400000 4334536 52 | 500000 5600428 53 | 600000 6749818 54 | 700000 8221148 55 | 800000 9875965 56 | 900000 10509550 57 | 1000000 12200395 58 | 2000000 23191355 59 | 3000000 32850517 60 | 4000000 44475632 61 | 5000000 57979690 62 | 6000000 70026761 63 | 7000000 77929165 64 | 8000000 95005424 65 | 9000000 106340911 66 | -------------------------------------------------------------------------------- /benchmarks/std_vector_small_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- 1 | # Benchmark: std_vector op: multiply_by_itself_one ap: sequential 2 | 3 | 20000000 168656417 4 | -------------------------------------------------------------------------------- /benchmarks/std_vector_very_small_object_multiply_by_itself_one_sequential.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gnzlbg/scattered/a9eaf8558136bcb64ceb02c0277dd4d767e8e9ae/benchmarks/std_vector_very_small_object_multiply_by_itself_one_sequential.dat -------------------------------------------------------------------------------- /benchmarks/template.gp: -------------------------------------------------------------------------------- 1 | set title "Accessing one data member" 2 | set xlabel "#of iterations [-]" 3 | set ylabel "Speed-up w.r.t. std::vector [-]" 4 | 5 | plot '< paste scattered_vector_very_small_object_multiply_by_itself_one_sequential.dat std_vector_very_small_object_multiply_by_itself_one_sequential.dat' u 1 : ($4/$2) w boxes t "very_small", '< paste scattered_vector_small_object_multiply_by_itself_one_sequential.dat std_vector_small_object_multiply_by_itself_one_sequential.dat' u 1 : ($4/$2) w boxes t "small" , '< paste scattered_vector_medium_object_multiply_by_itself_one_sequential.dat std_vector_medium_object_multiply_by_itself_one_sequential.dat' u 1 : ($4/$2) w boxes t "medium" , '< paste scattered_vector_large_object_multiply_by_itself_one_sequential.dat std_vector_large_object_multiply_by_itself_one_sequential.dat' u 1 : ($4/$2) w boxes t "large" 6 | 7 | set terminal svg size 400,300 enhanced font 'Tahoma,10' 8 | set output 'res.svg' 9 | replot 10 | set output 'dummy.svg' 11 | -------------------------------------------------------------------------------- /benchmarks/tests.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_BENCHMARK_HPP) 7 | #define SCATTERED_BENCHMARK_BENCHMARK_HPP 8 | 9 | template 14 | struct Benchmark { 15 | Benchmark() {} 16 | Benchmark(std::size_t size) : c(size) { 17 | Initializer{}(c); 18 | } 19 | void Benchmark() { 20 | AccessPattern{}(c, Operation{}); 21 | } 22 | Container c; 23 | }; 24 | 25 | static auto name(Benchmark) { 27 | return "Benchmark: operation" + name(Operation{}) 28 | + ", access: " + name(AccessPattern{}) 29 | + ", on type: " + name(Type{}) 30 | + ", stored in container: " + name(Container{}) 31 | + ", initialized with: " name(Initializer{}); 32 | } 33 | 34 | #endif // SCATTERED_BENCHMARK_BENCHMARK_HPP 35 | -------------------------------------------------------------------------------- /benchmarks/time_function.hpp: -------------------------------------------------------------------------------- 1 | // (C) Copyright Gonzalo Brito Gadeschi 2014 2 | // Use, modification and distribution are subject to the Boost Software License, 3 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 4 | // http://www.boost.org/LICENSE_1_0.txt). 5 | 6 | #if !defined(SCATTERED_BENCHMARK_TIME_FUNCTION_HPP) 7 | #define SCATTERED_BENCHMARK_TIME_FUNCTION_HPP 8 | 9 | #include 10 | 11 | using Time = std::chrono::nanoseconds; 12 | using Clock = std::chrono::high_resolution_clock; 13 | using TimePoint = std::chrono::time_point; 14 | 15 | template 16 | auto time_fn(F&& f) { 17 | const auto start = Clock::now(); 18 | f(); 19 | const auto end = Clock::now(); 20 | return std::chrono::duration_cast