├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── CMakeLists.txt.in ├── README.md ├── bench_construction.cpp ├── bench_delete.cpp ├── bench_dynamic_query.cpp ├── bench_insert.cpp ├── bench_insert_query.cpp ├── bench_knn.cpp ├── datasets └── utils.h ├── executable ├── CMakeLists.txt ├── parlayTest.cpp └── treeTime.cpp ├── include └── kdtree │ ├── binary-heap-layout │ └── bhlkdtree.h │ ├── cache-oblivious │ ├── cokdtree.h │ └── utils.h │ ├── log-tree │ ├── buffer.h │ └── logtree.h │ └── shared │ ├── bloom.h │ ├── box.h │ ├── dual.h │ ├── kdnode.h │ ├── kdtree.h │ ├── knnbuffer.h │ ├── macro.h │ └── utils.h ├── test ├── CMakeLists.txt ├── CMakeLists.txt.in ├── README.md ├── binary-heap-layout │ ├── BHL2DStructureTest.h │ ├── BHLTests.cpp │ ├── CMakeLists.txt │ └── main.cpp ├── cache-oblivious │ ├── CMakeLists.txt │ ├── CO2DStructureTest.h │ ├── COTests.cpp │ └── main.cpp ├── log-tree │ ├── CMakeLists.txt │ ├── LT2DDeleteTest.h │ ├── LT2DStructureTest.h │ ├── LTBasicStructure.cpp │ └── main.cpp ├── resources │ ├── 2d-UniformInSphere-10K.pbbs │ └── 2d-UniformInSphere-1k.pbbs └── shared │ ├── BasicStructure.h │ ├── CMakeLists.txt │ ├── QueryTest.h │ ├── Shared2DTest.h │ ├── SharedTests.cpp │ └── main.cpp └── utils ├── CMakeLists.txt └── external └── old_pargeo └── include ├── common ├── IO.h ├── geometry.h ├── geometryIO.h ├── get_time.h └── parse_command_line.h └── parlay /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | build 35 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "utils/external/xxHash"] 2 | path = utils/external/xxHash 3 | url = git@github.com:Cyan4973/xxHash.git 4 | [submodule "utils/external/pargeo"] 5 | path = utils/external/pargeo 6 | url = git@github.com:wangyiqiu/pargeo.git 7 | [submodule "utils/external/parlaylib"] 8 | path = utils/external/parlaylib 9 | url = git@github.com:wangyiqiu/parlaylib.git 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(kdtree) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | #set(CMAKE_ENABLE_EXPORTS true) 6 | 7 | # Issue with clang-tidy - it picks up errors from googletest 8 | #set(CMAKE_CXX_CLANG_TIDY 9 | #clang-tidy-9; 10 | #-header-filter=include/kdtree/.; 11 | #-checks=*; 12 | #-warnings-as-errors=*;) 13 | 14 | # Build Types 15 | set(available_build_types Debug Release RelWithDebInfo) 16 | if(NOT CMAKE_BUILD_TYPE) 17 | set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build Type ${available_build_types}" FORCE) 18 | message(STATUS "CMAKE_BUILD_TYPE is not set. Using default") 19 | message(STATUS "Available build types are: ${available_build_types}") 20 | endif() 21 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 22 | 23 | set(CMAKE_CXX_FLAGS "-Wall -Wextra -mcx16 -std=c++17") 24 | set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG") 25 | set(CMAKE_CXX_FLAGS_RELEASE "-O3 -march=native -DNDEBUG") 26 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g") 27 | 28 | # ------ Build Options ----- 29 | set(OMPFLAGS "-DPARLAY_OPENMP -fopenmp") 30 | set(CILKFLAGS "-DPARLAY_CILK -fcilkplus") 31 | set(PBBFLAGS "-DHOMEGROWN -pthread") 32 | if(PARALLEL_BUILD_TYPE EQUAL "OPENMP") 33 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OMPFLAGS}") 34 | elseif(PARALLEL_BUILD_TYPE EQUAL "CILK") 35 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CILKFLAGS}") 36 | else() 37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PBBFLAGS}") 38 | endif() 39 | 40 | # ------ kdtree options ----- 41 | if(DEFINED DUAL_KNN_MODE) 42 | if(DUAL_KNN_MODE STREQUAL "ATOMIC_LEAF") 43 | set(DUAL_KNN_MODE 0) 44 | elseif(DUAL_KNN_MODE STREQUAL "NONATOMIC_LEAF") 45 | set(DUAL_KNN_MODE 1) 46 | elseif(DUAL_KNN_MODE STREQUAL "ARRAY") 47 | set(DUAL_KNN_MODE 2) 48 | else() 49 | message(FATAL_ERROR "Invalid DUAL_KNN_MODE=${DUAL_KNN_MODE}") 50 | endif() 51 | add_compile_definitions(DUAL_KNN_MODE=${DUAL_KNN_MODE}) 52 | endif() 53 | 54 | if(DEFINED PARTITION_TYPE) 55 | if(PARTITION_TYPE STREQUAL "PARTITION_OBJECT_MEDIAN") 56 | set(PARTITION_TYPE 0) 57 | elseif(PARTITION_TYPE STREQUAL "PARTITION_SPATIAL_MEDIAN") 58 | set(PARTITION_TYPE 1) 59 | else() 60 | message(FATAL_ERROR "Invalid PARTITION_TYPE=${PARTITION_TYPE}") 61 | endif() 62 | add_compile_definitions(PARTITION_TYPE=${PARTITION_TYPE}) 63 | endif() 64 | 65 | if(DEFINED CLUSTER_SIZE) 66 | add_compile_definitions(CLUSTER_SIZE=${CLUSTER_SIZE}) 67 | endif() 68 | if(DEFINED ERASE_BASE_CASE) 69 | add_compile_definitions(ERASE_BASE_CASE=${ERASE_BASE_CASE}) 70 | endif() 71 | if(DEFINED RANGEQUERY_BASE_CASE) 72 | add_compile_definitions(RANGEQUERY_BASE_CASE=${RANGEQUERY_BASE_CASE}) 73 | endif() 74 | if(DEFINED BOUNDINGBOX_BASE_CASE) 75 | add_compile_definitions(BOUNDINGBOX_BASE_CASE=${BOUNDINGBOX_BASE_CASE}) 76 | endif() 77 | if(DEFINED DUALKNN_BASE_CASE) 78 | add_compile_definitions(DUALKNN_BASE_CASE=${DUALKNN_BASE_CASE}) 79 | endif() 80 | if(DEFINED CO_TOP_BUILD_BASE_CASE) 81 | add_compile_definitions(CO_TOP_BUILD_BASE_CASE=${CO_TOP_BUILD_BASE_CASE}) 82 | endif() 83 | if(DEFINED CO_BOTTOM_BUILD_BASE_CASE) 84 | add_compile_definitions(CO_BOTTOM_BUILD_BASE_CASE=${CO_BOTTOM_BUILD_BASE_CASE}) 85 | endif() 86 | if(DEFINED BHL_BUILD_BASE_CASE) 87 | add_compile_definitions(BHL_BUILD_BASE_CASE=${BHL_BUILD_BASE_CASE}) 88 | endif() 89 | 90 | OPTION(ALL_USE_BLOOM "all use bloom" OFF) 91 | if(ALL_USE_BLOOM) 92 | add_compile_definitions(ALL_USE_BLOOM) 93 | endif() 94 | 95 | OPTION(LOGTREE_USE_BLOOM "logtree use bloom" OFF) 96 | if(LOGTREE_USE_BLOOM) 97 | add_compile_definitions(LOGTREE_USE_BLOOM) 98 | endif() 99 | 100 | OPTION(BLOOM_FILTER_BUILD_COPY "logtree filter copy" OFF) 101 | if(BLOOM_FILTER_BUILD_COPY) 102 | add_compile_definitions(BLOOM_FILTER_BUILD_COPY) 103 | endif() 104 | 105 | message(STATUS "--------------- General configuration -------------") 106 | message(STATUS "CMake Generator: ${CMAKE_GENERATOR}") 107 | message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") 108 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 109 | message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") 110 | message(STATUS "CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}") 111 | message(STATUS "CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") 112 | message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 113 | message(STATUS "CMAKE_EXE_LINKER_FLAGS ${CMAKE_CXX_LINKER_FLAGS}") 114 | message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}" ) 115 | 116 | # ------ Library ------ 117 | add_library(kdtree INTERFACE) 118 | set(KDTREE_INCLUDE_DIR "include/") 119 | target_include_directories(kdtree INTERFACE ${KDTREE_INCLUDE_DIR}) 120 | target_link_libraries(kdtree INTERFACE external) 121 | target_compile_features(kdtree INTERFACE cxx_std_17) 122 | 123 | # ------ External ------ 124 | add_subdirectory(utils) 125 | 126 | # ------ Targets ------ 127 | enable_testing() 128 | add_subdirectory(test) 129 | add_subdirectory(executable) 130 | add_subdirectory(benchmark) 131 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rahul Yesantharao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parallel, Batch-Dynamic kd-Tree 2 | ## About 3 | This repository contains code for our paper: Parallel Batch-Dynamic kd-Trees. It contains an implementation of a logarithmically-structured parallel batch-dynamic kd-tree as well as several baseline implementations of parallel batch-dynamic kd-trees. 4 | 5 | ## Development 6 | We use [ParlayLib](https://github.com/cmuparlay/parlaylib), a wonderful library developed at CMU for multi-core parallel programming. We also use [xxHash](https://github.com/Cyan4973/xxHash) for a 64-bit hash function. These modules are included in the project as submodules, initialize them before building the project: 7 | ``` 8 | git submodule init 9 | git submodule update 10 | ``` 11 | 12 | We use CMake as the build system. To build the project: 13 | ``` 14 | mkdir build 15 | cd build 16 | cmake .. 17 | make -j 18 | ``` 19 | See the top level [CMakeLists](https://github.com/rahulyesantharao/batch-dynamic-kdtree/blob/main/CMakeLists.txt#L41) for various build options that can be included with the `cmake` command above. 20 | 21 | After the build completes, you will find executables in the nested directories of `build/`. Comprehensive tests can be found under `build/test/` for all the implemented data structures. Benchmarks are written using [Google Benchmark](https://github.com/google/benchmark) and can be found under `build/benchmark/`. They can be run using GoogleBenchmark syntax; for example, to run the construction benchmark over the BDL-tree with a 10M, 2D dataset, use 22 | ``` 23 | ./bench_construction --benchmark_filter="bench_construction<2, LogTree_t<2>>/10000000/100/0/real_time" 24 | ``` 25 | 26 | You can view all the different benchmarks under a given executable by passing the flag `--benchmark_list_tests`. Example datasets can be found [here](https://github.com/rahulyesantharao/batch-dynamic-kdtree/tree/main/test/resources). 27 | 28 | ## Support 29 | This code is still in a research-phase. Please contact the developers or paper authors if you encounter any problems. 30 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | set(CMAKE_CXX_STANDARD 17) 3 | 4 | # check whether googletest is locally installed, if not download and fetch 5 | message(STATUS "--------------- GoogleBenchmark -------------") 6 | find_package(benchmark CONFIG) 7 | if(NOT benchmark_FOUND) 8 | # new way of including googletest 9 | # Download and unpack googletest at configure time 10 | set(BENCHMARK_ENABLE_LIBPFM ON) 11 | set(BENCHMARK_ENABLE_GTEST_TESTS OFF) 12 | configure_file(CMakeLists.txt.in googlebenchmark-download/CMakeLists.txt) 13 | execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . 14 | RESULT_VARIABLE result 15 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/benchmark/googlebenchmark-download ) 16 | if(result) 17 | message(FATAL_ERROR "CMake step for googlebenchmark failed: ${result}") 18 | endif() 19 | execute_process(COMMAND ${CMAKE_COMMAND} --build . --config Release 20 | RESULT_VARIABLE result 21 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/benchmark/googlebenchmark-download ) 22 | if(result) 23 | message(FATAL_ERROR "Build step for googlebenchmark failed: ${result}") 24 | endif() 25 | 26 | # Prevent overriding the parent project's compiler/linker 27 | # settings on Windows 28 | #set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 29 | 30 | # Add googletest directly to our build. This defines 31 | # the gtest and gtest_main targets. 32 | add_subdirectory(${CMAKE_BINARY_DIR}/googlebenchmark-src 33 | ${CMAKE_BINARY_DIR}/googlebenchmark-build 34 | EXCLUDE_FROM_ALL) 35 | set(benchmark_LIBRARIES "benchmark") 36 | set(benchmark_main_LIBRARIES "benchmark_main") 37 | else() 38 | message(STATUS "using locally installed GoogleBenchmark") 39 | #set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 40 | set(benchmark_LIBRARIES benchmark::benchmark) 41 | endif() 42 | 43 | message(STATUS "--------------- Building Benchmarks -------------") 44 | set(NUMA_COMMAND numactl -i all) 45 | function(add_benchmark NAME) 46 | add_executable(bench_${NAME} bench_${NAME}.cpp) 47 | target_link_libraries(bench_${NAME} PRIVATE kdtree ${benchmark_main_LIBRARIES}) 48 | target_compile_options(bench_${NAME} PRIVATE -Wall -Wextra -Wfatal-errors -march=native) 49 | 50 | # numactl 51 | add_custom_target(numactl_bench_${NAME} 52 | COMMAND ${NUMA_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/bench_${NAME} --benchmark_counters_tabular=true --benchmark_out_format=json 53 | ) 54 | add_dependencies(numactl_bench_${NAME} bench_${NAME}) 55 | endfunction() 56 | 57 | # Add benchmark file 58 | add_benchmark(knn) 59 | add_benchmark(insert) 60 | add_benchmark(construction) 61 | add_benchmark(delete) 62 | add_benchmark(insert_query) 63 | add_benchmark(dynamic_query) 64 | 65 | # copy resources 66 | file(COPY datasets DESTINATION ${CMAKE_BINARY_DIR}/benchmark) 67 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7) 2 | 3 | project(googlebenchmark-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googlebenchmark 7 | GIT_REPOSITORY https://github.com/google/benchmark.git 8 | GIT_TAG main 9 | SOURCE_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-src" 10 | BINARY_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-build" 11 | CONFIGURE_COMMAND "" 12 | BUILD_COMMAND "" 13 | INSTALL_COMMAND "" 14 | TEST_COMMAND "" 15 | ) 16 | -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarks 2 | 3 | ## Disable CPU frequency scaling 4 | See [here](https://github.com/google/benchmark#disabling-cpu-frequency-scaling). 5 | 6 | tldr: 7 | ``` 8 | sudo cpupower frequency-set --governor performance 9 | ./mybench 10 | sudo cpupower frequency-set --governor powersave 11 | ``` 12 | -------------------------------------------------------------------------------- /benchmark/bench_construction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "common/get_time.h" 5 | #include "common/geometry.h" 6 | #include "common/geometryIO.h" 7 | #include "common/parse_command_line.h" 8 | 9 | #include "kdtree/cache-oblivious/cokdtree.h" 10 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 11 | #include "kdtree/log-tree/logtree.h" 12 | #include "kdtree/shared/dual.h" 13 | 14 | #include 15 | #include "./utils.h" 16 | 17 | using namespace benchIO; 18 | 19 | using coord = double; 20 | 21 | // Define another benchmark 22 | template 23 | static void bench_construction(benchmark::State& state) { 24 | auto size = state.range(0); 25 | auto percentage = state.range(1); 26 | DSType ds_type = (DSType)state.range(2); 27 | 28 | auto points_ = BenchmarkDS(size, ds_type); 29 | const auto& points = points_; 30 | auto point_slice = points.cut(0, (points.size() * percentage) / 100); 31 | 32 | // benchmark 33 | for (auto _ : state) { 34 | { 35 | Tree tree(point_slice); 36 | state.PauseTiming(); 37 | } 38 | state.ResumeTiming(); 39 | } 40 | } 41 | 42 | // Instantiate benchmarks 43 | BENCH(construction, 2, COTree_t<2>) 44 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 45 | BENCH(construction, 2, BHLTree_t<2>) 46 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 47 | BENCH(construction, 2, LogTree_t<2>) 48 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 49 | 50 | BENCH(construction, 3, COTree_t<3>)->ArgsProduct({{10'000'000}, {100, 50}, {DS_GEO_LIFE}}); 51 | BENCH(construction, 3, BHLTree_t<3>)->ArgsProduct({{10'000'000}, {100, 50}, {DS_GEO_LIFE}}); 52 | BENCH(construction, 3, LogTree_t<3>)->ArgsProduct({{10'000'000}, {100, 50}, {DS_GEO_LIFE}}); 53 | 54 | BENCH(construction, 5, COTree_t<5>) 55 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 56 | BENCH(construction, 5, BHLTree_t<5>) 57 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 58 | BENCH(construction, 5, LogTree_t<5>) 59 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 60 | 61 | BENCH(construction, 7, COTree_t<7>) 62 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 63 | BENCH(construction, 7, BHLTree_t<7>) 64 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 65 | BENCH(construction, 7, LogTree_t<7>) 66 | ->ArgsProduct({{10'000'000}, {100, 50}, {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 67 | 68 | BENCH(construction, 10, COTree_t<10>)->ArgsProduct({{10'000'000}, {100}, {DS_HT}}); 69 | BENCH(construction, 10, BHLTree_t<10>)->ArgsProduct({{10'000'000}, {100}, {DS_HT}}); 70 | BENCH(construction, 10, LogTree_t<10>)->ArgsProduct({{10'000'000}, {100}, {DS_HT}}); 71 | 72 | BENCH(construction, 16, COTree_t<16>)->ArgsProduct({{10'000'000}, {100}, {DS_CHEM}}); 73 | BENCH(construction, 16, BHLTree_t<16>)->ArgsProduct({{10'000'000}, {100}, {DS_CHEM}}); 74 | BENCH(construction, 16, LogTree_t<16>)->ArgsProduct({{10'000'000}, {100}, {DS_CHEM}}); 75 | -------------------------------------------------------------------------------- /benchmark/bench_delete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "parlay/random.h" 5 | #include "common/get_time.h" 6 | #include "common/geometry.h" 7 | #include "common/geometryIO.h" 8 | #include "common/parse_command_line.h" 9 | 10 | #include "kdtree/cache-oblivious/cokdtree.h" 11 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 12 | #include "kdtree/log-tree/logtree.h" 13 | #include "kdtree/shared/dual.h" 14 | 15 | #include 16 | #include "./utils.h" 17 | 18 | using namespace benchIO; 19 | 20 | using coord = double; 21 | 22 | // Define another benchmark 23 | template 24 | static void bench_delete_(benchmark::State& state) { 25 | auto size = state.range(0); 26 | auto percentage = state.range(1); 27 | DSType ds_type = (DSType)state.range(2); 28 | 29 | parlay::sequence> points; 30 | points = BenchmarkDS(size, ds_type); 31 | 32 | // generate (deterministic) random sample to delete 33 | int del_size = (points.size() * percentage) / 100; 34 | auto to_delete = random_shuffle(points); // random shuffle 35 | std::vector>> del_arr; 36 | size_t pos = 0; 37 | while (pos < points.size()) { 38 | auto next_pos = std::min(pos + del_size, points.size()); 39 | parlay::sequence> pts; 40 | pts.assign(to_delete.cut(pos, next_pos)); 41 | del_arr.push_back(std::move(pts)); 42 | pos = next_pos; 43 | } 44 | 45 | // benchmark 46 | for (auto _ : state) { 47 | { 48 | state.PauseTiming(); 49 | Tree tree(points); 50 | state.ResumeTiming(); 51 | 52 | // actual benchmark 53 | for (size_t i = 0; i < del_arr.size(); i++) { 54 | tree.bulk_erase(del_arr[i]); 55 | } 56 | state.PauseTiming(); 57 | } 58 | state.ResumeTiming(); 59 | } 60 | } 61 | 62 | // Instantiate benchmarks 63 | BENCH(delete_, 2, COTree_t<2>) 64 | ->ArgsProduct({{10'000'000}, 65 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 66 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 67 | BENCH(delete_, 2, BHLTree_t<2>) 68 | ->ArgsProduct({{10'000'000}, 69 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 70 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 71 | BENCH(delete_, 2, LogTree_t<2>) 72 | ->ArgsProduct({{10'000'000}, 73 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 74 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 75 | 76 | BENCH(delete_, 3, COTree_t<3>) 77 | ->ArgsProduct({{10'000'000}, 78 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 79 | {DS_GEO_LIFE}}); 80 | BENCH(delete_, 3, BHLTree_t<3>) 81 | ->ArgsProduct({{10'000'000}, 82 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 83 | {DS_GEO_LIFE}}); 84 | BENCH(delete_, 3, LogTree_t<3>) 85 | ->ArgsProduct({{10'000'000}, 86 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 87 | {DS_GEO_LIFE}}); 88 | 89 | BENCH(delete_, 5, COTree_t<5>) 90 | ->ArgsProduct({{10'000'000}, 91 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 92 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 93 | BENCH(delete_, 5, BHLTree_t<5>) 94 | ->ArgsProduct({{10'000'000}, 95 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 96 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 97 | BENCH(delete_, 5, LogTree_t<5>) 98 | ->ArgsProduct({{10'000'000}, 99 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 100 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 101 | 102 | BENCH(delete_, 7, COTree_t<7>) 103 | ->ArgsProduct({{10'000'000}, 104 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 105 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 106 | BENCH(delete_, 7, BHLTree_t<7>) 107 | ->ArgsProduct({{10'000'000}, 108 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 109 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 110 | BENCH(delete_, 7, LogTree_t<7>) 111 | ->ArgsProduct({{10'000'000}, 112 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 113 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 114 | 115 | BENCH(delete_, 10, COTree_t<10>) 116 | ->ArgsProduct({{10'000'000}, 117 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 118 | {DS_HT}}); 119 | BENCH(delete_, 10, BHLTree_t<10>) 120 | ->ArgsProduct({{10'000'000}, 121 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 122 | {DS_HT}}); 123 | BENCH(delete_, 10, LogTree_t<10>) 124 | ->ArgsProduct({{10'000'000}, 125 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 126 | {DS_HT}}); 127 | 128 | BENCH(delete_, 16, COTree_t<16>) 129 | ->ArgsProduct({{10'000'000}, 130 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 131 | {DS_CHEM}}); 132 | BENCH(delete_, 16, BHLTree_t<16>) 133 | ->ArgsProduct({{10'000'000}, 134 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 135 | {DS_CHEM}}); 136 | BENCH(delete_, 16, LogTree_t<16>) 137 | ->ArgsProduct({{10'000'000}, 138 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 139 | {DS_CHEM}}); 140 | -------------------------------------------------------------------------------- /benchmark/bench_dynamic_query.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "common/get_time.h" 5 | #include "common/geometry.h" 6 | #include "common/geometryIO.h" 7 | #include "common/parse_command_line.h" 8 | 9 | #include "kdtree/cache-oblivious/cokdtree.h" 10 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 11 | #include "kdtree/log-tree/logtree.h" 12 | #include "kdtree/shared/dual.h" 13 | 14 | #include 15 | #include "./utils.h" 16 | 17 | using namespace benchIO; 18 | 19 | using coord = double; 20 | 21 | //#define SHOW_TIMINGS 22 | #define SMALL_BATCH_DELETE 23 | 24 | // Define another benchmark 25 | template 26 | static void bench_dynamic_query(benchmark::State& state) { 27 | auto size = state.range(0); 28 | auto batch_percentage = state.range(1); 29 | auto k = state.range(2); 30 | DSType ds_type = (DSType)state.range(3); 31 | 32 | auto points_ = BenchmarkDS(size, ds_type, false); 33 | const auto& points = points_; 34 | 35 | int log2size = (int)std::ceil(std::log2(points.size())); 36 | size_t div_size = (points.size() * batch_percentage) / 100; 37 | size_t initial_div_size = (points.size() * 0.5) / 100; 38 | 39 | constexpr size_t sub_division = 4; 40 | auto del_points = random_shuffle(points); 41 | #ifdef SMALL_BATCH_DELETE 42 | std::vector>> del_arr[sub_division]; 43 | size_t del_pos = 0; 44 | for (size_t sd = 1; sd < sub_division; sd++) { 45 | while (del_pos < (points.size() * sd) / sub_division) { 46 | auto next_pos = std::min(del_pos + initial_div_size, points.size()); 47 | parlay::sequence> pts; 48 | pts.assign(del_points.cut(del_pos, next_pos)); 49 | del_arr[sd].push_back(std::move(pts)); 50 | del_pos = next_pos; 51 | } 52 | } 53 | #else 54 | std::vector>> del_arr; 55 | for (size_t sd = 1; sd < sub_division; sd++) { 56 | parlay::sequence> pts; 57 | pts.assign(del_points.cut((points.size() * (sd - 1)) / sub_division, 58 | (points.size() * sd) / sub_division)); 59 | del_arr.push_back(std::move(pts)); 60 | } 61 | #endif 62 | 63 | // benchmark 64 | for (auto _ : state) { 65 | { 66 | state.PauseTiming(); 67 | Tree tree(log2size); 68 | state.ResumeTiming(); 69 | 70 | timer t("[dyn iq]"); 71 | auto timestamp = [&](std::string name, size_t idx) { 72 | auto ts = t.get_next(); 73 | #ifdef SHOW_TIMINGS 74 | std::cout << "[dyn iq] " << name << "_" << idx << " DONE: " << ts << std::endl; 75 | #endif 76 | state.counters[name + "_" + std::to_string(idx)] = ts; 77 | }; 78 | 79 | // INSERT 80 | size_t pos = 0; 81 | for (size_t sd = 0; sd < sub_division; sd++) { 82 | while (pos < (points.size() * (sd + 1)) / 4) { 83 | auto next_pos = std::min(pos + initial_div_size, points.size()); 84 | tree.insert(points.cut(pos, next_pos)); 85 | pos = next_pos; 86 | } 87 | timestamp("insert", sd); 88 | 89 | // QUERY 90 | if (log) 91 | tree.template knn3<0, 0>(points, k); 92 | else 93 | tree.template knn<0, 0>(points, k); 94 | timestamp("knn", sd); 95 | } 96 | 97 | // DELETE 98 | for (size_t sd = 1; sd < sub_division; sd++) { 99 | #ifdef SMALL_BATCH_DELETE 100 | for (auto& d : del_arr[sd]) { 101 | tree.bulk_erase(d); 102 | } 103 | #else 104 | tree.bulk_erase(del_arr[sd - 1]); 105 | #endif 106 | timestamp("delete", sd); 107 | 108 | // QUERY 109 | if (log) 110 | tree.template knn3<0, 0>(points, k); 111 | else 112 | tree.template knn<0, 0>(points, k); 113 | timestamp("knn", sd + sub_division - 1); 114 | } 115 | 116 | state.PauseTiming(); 117 | } 118 | state.ResumeTiming(); 119 | } 120 | } 121 | 122 | // Instantiate benchmarks 123 | BENCH(dynamic_query, 2, BHLTree_t<2>, false) 124 | ->ArgsProduct({{10'000'000}, 125 | {1, 2, 3, 5}, 126 | //{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 127 | {5}, 128 | //{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 129 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 130 | BENCH(dynamic_query, 2, LogTree_t<2>, true) 131 | ->ArgsProduct({{10'000'000}, 132 | {1, 2, 3, 5}, 133 | //{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 134 | {5}, 135 | //{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 136 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 137 | // BENCH(dynamic_query, 3) 138 | //->ArgsProduct({{10'000'000}, 139 | //{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 140 | //{5}, 141 | ////{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 142 | //{DS_GEO_LIFE}}); 143 | // BENCH(dynamic_query, 5) 144 | //->ArgsProduct({{10'000'000}, 145 | //{10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 146 | //{5}, 147 | ////{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 148 | //{DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 149 | BENCH(dynamic_query, 5, BHLTree_t<5>, false) 150 | ->ArgsProduct({{10'000'000}, 151 | {1, 2, 3, 5}, 152 | //{1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 153 | // 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 154 | {5}, 155 | //{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 156 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 157 | BENCH(dynamic_query, 5, LogTree_t<5>, true) 158 | ->ArgsProduct({{10'000'000}, 159 | {1, 2, 3, 5}, 160 | //{1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 161 | // 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 162 | {5}, 163 | //{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 164 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 165 | -------------------------------------------------------------------------------- /benchmark/bench_insert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "common/get_time.h" 5 | #include "common/geometry.h" 6 | #include "common/geometryIO.h" 7 | #include "common/parse_command_line.h" 8 | 9 | #include "kdtree/cache-oblivious/cokdtree.h" 10 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 11 | #include "kdtree/log-tree/logtree.h" 12 | #include "kdtree/shared/dual.h" 13 | 14 | #include 15 | #include "./utils.h" 16 | 17 | using namespace benchIO; 18 | 19 | using coord = double; 20 | 21 | // Define another benchmark 22 | template 23 | static void bench_insert(benchmark::State& state) { 24 | auto size = state.range(0); 25 | auto batch_percentage = state.range(1); 26 | DSType ds_type = (DSType)state.range(2); 27 | 28 | auto points_ = BenchmarkDS(size, ds_type); 29 | const auto& points = points_; 30 | 31 | int log2size = (int)std::ceil(std::log2(points.size())); 32 | size_t div_size = points.size() * batch_percentage / 100; 33 | 34 | // benchmark 35 | for (auto _ : state) { 36 | { 37 | state.PauseTiming(); 38 | Tree tree(log2size); 39 | state.ResumeTiming(); 40 | 41 | // actual benchmark 42 | size_t pos = 0; 43 | while (pos < points.size()) { 44 | auto next_pos = std::min(pos + div_size, points.size()); 45 | tree.insert(points.cut(pos, next_pos)); 46 | pos = next_pos; 47 | } 48 | 49 | state.PauseTiming(); 50 | } 51 | state.ResumeTiming(); 52 | } 53 | } 54 | 55 | // Instantiate benchmarks 56 | BENCH(insert, 2, COTree_t<2>) 57 | ->ArgsProduct({{10'000'000}, 58 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 59 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 60 | BENCH(insert, 2, BHLTree_t<2>) 61 | ->ArgsProduct({{10'000'000}, 62 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 63 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 64 | BENCH(insert, 2, LogTree_t<2>) 65 | ->ArgsProduct({{10'000'000}, 66 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 67 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 68 | 69 | BENCH(insert, 3, COTree_t<3>) 70 | ->ArgsProduct({{10'000'000}, 71 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 72 | {DS_GEO_LIFE}}); 73 | BENCH(insert, 3, BHLTree_t<3>) 74 | ->ArgsProduct({{10'000'000}, 75 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 76 | {DS_GEO_LIFE}}); 77 | BENCH(insert, 3, LogTree_t<3>) 78 | ->ArgsProduct({{10'000'000}, 79 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 80 | {DS_GEO_LIFE}}); 81 | 82 | BENCH(insert, 5, COTree_t<5>) 83 | ->ArgsProduct({{10'000'000}, 84 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 85 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 86 | BENCH(insert, 5, BHLTree_t<5>) 87 | ->ArgsProduct({{10'000'000}, 88 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 89 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 90 | BENCH(insert, 5, LogTree_t<5>) 91 | ->ArgsProduct({{10'000'000}, 92 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 93 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 94 | 95 | BENCH(insert, 7, COTree_t<7>) 96 | ->ArgsProduct({{10'000'000}, 97 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 98 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 99 | BENCH(insert, 7, BHLTree_t<7>) 100 | ->ArgsProduct({{10'000'000}, 101 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 102 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 103 | BENCH(insert, 7, LogTree_t<7>) 104 | ->ArgsProduct({{10'000'000}, 105 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 106 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 107 | 108 | BENCH(insert, 10, COTree_t<10>) 109 | ->ArgsProduct({{10'000'000}, 110 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 111 | {DS_HT}}); 112 | BENCH(insert, 10, BHLTree_t<10>) 113 | ->ArgsProduct({{10'000'000}, 114 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 115 | {DS_HT}}); 116 | BENCH(insert, 10, LogTree_t<10>) 117 | ->ArgsProduct({{10'000'000}, 118 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 119 | {DS_HT}}); 120 | 121 | BENCH(insert, 16, COTree_t<16>) 122 | ->ArgsProduct({{10'000'000}, 123 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 124 | {DS_CHEM}}); 125 | BENCH(insert, 16, BHLTree_t<16>) 126 | ->ArgsProduct({{10'000'000}, 127 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 128 | {DS_CHEM}}); 129 | BENCH(insert, 16, LogTree_t<16>) 130 | ->ArgsProduct({{10'000'000}, 131 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 132 | {DS_CHEM}}); 133 | -------------------------------------------------------------------------------- /benchmark/bench_insert_query.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "common/get_time.h" 5 | #include "common/geometry.h" 6 | #include "common/geometryIO.h" 7 | #include "common/parse_command_line.h" 8 | 9 | #include "kdtree/cache-oblivious/cokdtree.h" 10 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 11 | #include "kdtree/log-tree/logtree.h" 12 | #include "kdtree/shared/dual.h" 13 | 14 | #include 15 | #include "./utils.h" 16 | 17 | using namespace benchIO; 18 | 19 | using coord = double; 20 | 21 | // Define another benchmark 22 | template 23 | static void bench_insert_query(benchmark::State& state) { 24 | auto size = state.range(0); 25 | auto batch_percentage = state.range(1); 26 | auto k = state.range(2); 27 | DSType ds_type = (DSType)state.range(3); 28 | 29 | auto points_ = BenchmarkDS(size, ds_type, false); 30 | const auto& points = points_; 31 | 32 | int log2size = (int)std::ceil(std::log2(points.size())); 33 | size_t div_size = points.size() * batch_percentage / 100; 34 | 35 | // benchmark 36 | for (auto _ : state) { 37 | { 38 | state.PauseTiming(); 39 | Tree tree(log2size); 40 | state.ResumeTiming(); 41 | 42 | // INSERT 43 | size_t pos = 0; 44 | while (pos < points.size()) { 45 | auto next_pos = std::min(pos + div_size, points.size()); 46 | tree.insert(points.cut(pos, next_pos)); 47 | pos = next_pos; 48 | } 49 | 50 | // QUERY 51 | tree.template knn<0, 0>(points, k); 52 | state.PauseTiming(); 53 | } 54 | state.ResumeTiming(); 55 | } 56 | } 57 | 58 | // Instantiate benchmarks 59 | BENCH(insert_query, 2, COTree_t<2>) 60 | ->ArgsProduct({{10'000'000}, 61 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 62 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 63 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 64 | BENCH(insert_query, 2, BHLTree_t<2>) 65 | ->ArgsProduct({{10'000'000}, 66 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 67 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 68 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 69 | BENCH(insert_query, 2, LogTree_t<2>) 70 | ->ArgsProduct({{10'000'000}, 71 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 72 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 73 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 74 | 75 | BENCH(insert_query, 3, COTree_t<3>) 76 | ->ArgsProduct({{10'000'000}, 77 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 78 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 79 | {DS_GEO_LIFE}}); 80 | BENCH(insert_query, 3, BHLTree_t<3>) 81 | ->ArgsProduct({{10'000'000}, 82 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 83 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 84 | {DS_GEO_LIFE}}); 85 | 86 | BENCH(insert_query, 3, LogTree_t<3>) 87 | ->ArgsProduct({{10'000'000}, 88 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 89 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 90 | {DS_GEO_LIFE}}); 91 | 92 | BENCH(insert_query, 5, COTree_t<5>) 93 | ->ArgsProduct({{10'000'000}, 94 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 95 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 96 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 97 | BENCH(insert_query, 5, BHLTree_t<5>) 98 | ->ArgsProduct({{10'000'000}, 99 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 100 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 101 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 102 | 103 | BENCH(insert_query, 5, LogTree_t<5>) 104 | ->ArgsProduct({{10'000'000}, 105 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 106 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 107 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 108 | 109 | BENCH(insert_query, 7, COTree_t<7>) 110 | ->ArgsProduct({{10'000'000}, 111 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 112 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 113 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 114 | BENCH(insert_query, 7, BHLTree_t<7>) 115 | ->ArgsProduct({{10'000'000}, 116 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 117 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 118 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 119 | BENCH(insert_query, 7, LogTree_t<7>) 120 | ->ArgsProduct({{10'000'000}, 121 | {10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100}, 122 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 123 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 124 | -------------------------------------------------------------------------------- /benchmark/bench_knn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "parlay/parallel.h" 4 | #include "common/get_time.h" 5 | #include "common/geometry.h" 6 | #include "common/geometryIO.h" 7 | #include "common/parse_command_line.h" 8 | 9 | #include "kdtree/cache-oblivious/cokdtree.h" 10 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 11 | #include "kdtree/log-tree/logtree.h" 12 | #include "kdtree/shared/dual.h" 13 | 14 | #include 15 | #include "./utils.h" 16 | 17 | using namespace benchIO; 18 | 19 | using coord = double; 20 | 21 | // Arguments: {k_type, size, k} 22 | // template 23 | // static std::tuple>, int> unpack(benchmark::State& state) { 24 | //// unpack args 25 | // auto size = state.range(0); 26 | // auto k = state.range(1); 27 | // std::cout << "(size, k, dim) = (" << size << ", " << k << ", " << dim << ")" << std::endl; 28 | 29 | //// construct tree 30 | // parlay::sequence> points; 31 | // points = BenchmarkDS(size); 32 | // Tree tree(points); 33 | 34 | // return {tree, points, k}; 35 | //} 36 | 37 | // Define another benchmark 38 | template 39 | static void bench_knn(benchmark::State& state) { 40 | auto size = state.range(0); 41 | auto k = state.range(1); 42 | DSType ds_type = (DSType)state.range(2); 43 | parlay::sequence> points; 44 | points = BenchmarkDS(size, ds_type); 45 | Tree tree(points); 46 | 47 | // benchmark 48 | for (auto _ : state) { 49 | RUN_AND_CLEAR((tree.template knn<(k_type & 2), (k_type & 1)>(points, k))); 50 | } 51 | } 52 | 53 | // Define another benchmark 54 | template 55 | static void bench_knn2(benchmark::State& state) { 56 | typedef LogTree_t Tree; 57 | auto size = state.range(0); 58 | auto k = state.range(1); 59 | DSType ds_type = (DSType)state.range(2); 60 | parlay::sequence> points; 61 | points = BenchmarkDS(size, ds_type); 62 | Tree tree(points); 63 | 64 | // benchmark 65 | for (auto _ : state) { 66 | RUN_AND_CLEAR((tree.template knn2<(k_type & 2), (k_type & 1)>(points, k))); 67 | } 68 | } 69 | 70 | // Define another benchmark 71 | template 72 | static void bench_knn3(benchmark::State& state) { 73 | typedef LogTree_t Tree; 74 | auto size = state.range(0); 75 | auto k = state.range(1); 76 | DSType ds_type = (DSType)state.range(2); 77 | parlay::sequence> points; 78 | points = BenchmarkDS(size, ds_type); 79 | Tree tree(points); 80 | 81 | // benchmark 82 | for (auto _ : state) { 83 | RUN_AND_CLEAR((tree.template knn3<(k_type & 2), (k_type & 1)>(points, k))); 84 | } 85 | } 86 | 87 | template 88 | static void bench_dual_knn(benchmark::State& state) { 89 | // typedef LogTree_t Tree; 90 | auto size = state.range(0); 91 | auto k = state.range(1); 92 | DSType ds_type = (DSType)state.range(2); 93 | parlay::sequence> points; 94 | points = BenchmarkDS(size, ds_type); 95 | Tree tree(points); 96 | 97 | // benchmark 98 | for (auto _ : state) { 99 | RUN_AND_CLEAR(dualKnn(points, tree, k)); 100 | } 101 | } 102 | 103 | // Instantiate benchmarks 104 | BENCH(knn, 2, COTree_t<2>, 0) 105 | ->ArgsProduct({{10'000'000}, 106 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 107 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 108 | BENCH(knn, 2, BHLTree_t<2>, 0) 109 | ->ArgsProduct({{10'000'000}, 110 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 111 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 112 | BENCH(knn, 2, LogTree_t<2>, 0) 113 | ->ArgsProduct({{10'000'000}, 114 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 115 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 116 | BENCH(knn2, 2, 0) 117 | ->ArgsProduct({{10'000'000}, 118 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 119 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 120 | BENCH(knn3, 2, 0) 121 | ->ArgsProduct({{10'000'000}, 122 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 123 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 124 | BENCH(dual_knn, 2, COTree_t<2>) 125 | ->ArgsProduct({{10'000'000}, 126 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 127 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 128 | BENCH(dual_knn, 2, BHLTree_t<2>) 129 | ->ArgsProduct({{10'000'000}, 130 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 131 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 132 | BENCH(dual_knn, 2, LogTree_t<2>) 133 | ->ArgsProduct({{10'000'000}, 134 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 135 | {DS_UNIFORM_FILL, DS_UNIFORM_SPHERE, DS_VISUAL_VAR}}); 136 | 137 | BENCH(knn, 3, COTree_t<3>, 0) 138 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 139 | BENCH(knn, 3, BHLTree_t<3>, 0) 140 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 141 | BENCH(knn, 3, LogTree_t<3>, 0) 142 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 143 | BENCH(knn2, 3, 0)->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 144 | BENCH(knn3, 3, 0)->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 145 | BENCH(dual_knn, 3, COTree_t<3>) 146 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 147 | BENCH(dual_knn, 3, BHLTree_t<3>) 148 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 149 | BENCH(dual_knn, 3, LogTree_t<3>) 150 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_GEO_LIFE}}); 151 | 152 | BENCH(knn, 5, COTree_t<5>, 0) 153 | ->ArgsProduct({{10'000'000}, 154 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 155 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 156 | BENCH(knn, 5, BHLTree_t<5>, 0) 157 | ->ArgsProduct({{10'000'000}, 158 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 159 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 160 | BENCH(knn, 5, LogTree_t<5>, 0) 161 | ->ArgsProduct({{10'000'000}, 162 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 163 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 164 | BENCH(knn2, 5, 0) 165 | ->ArgsProduct({{10'000'000}, 166 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 167 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 168 | BENCH(knn3, 5, 0) 169 | ->ArgsProduct({{10'000'000}, 170 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 171 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 172 | BENCH(dual_knn, 5, COTree_t<5>) 173 | ->ArgsProduct({{10'000'000}, 174 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 175 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 176 | BENCH(dual_knn, 5, BHLTree_t<5>) 177 | ->ArgsProduct({{10'000'000}, 178 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 179 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 180 | BENCH(dual_knn, 5, LogTree_t<5>) 181 | ->ArgsProduct({{10'000'000}, 182 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 183 | {DS_UNIFORM_FILL, DS_VISUAL_VAR}}); 184 | 185 | BENCH(knn, 7, COTree_t<7>, 0) 186 | ->ArgsProduct({{10'000'000}, 187 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 188 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 189 | BENCH(knn, 7, BHLTree_t<7>, 0) 190 | ->ArgsProduct({{10'000'000}, 191 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 192 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 193 | BENCH(knn, 7, LogTree_t<7>, 0) 194 | ->ArgsProduct({{10'000'000}, 195 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 196 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 197 | BENCH(knn2, 7, 0) 198 | ->ArgsProduct({{10'000'000}, 199 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 200 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 201 | BENCH(knn3, 7, 0) 202 | ->ArgsProduct({{10'000'000}, 203 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 204 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 205 | BENCH(dual_knn, 7, COTree_t<7>) 206 | ->ArgsProduct({{10'000'000}, 207 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 208 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 209 | BENCH(dual_knn, 7, BHLTree_t<7>) 210 | ->ArgsProduct({{10'000'000}, 211 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 212 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 213 | BENCH(dual_knn, 7, LogTree_t<7>) 214 | ->ArgsProduct({{10'000'000}, 215 | {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 216 | {DS_UNIFORM_FILL, DS_VISUAL_VAR, DS_HOUSE_HOLD}}); 217 | 218 | BENCH(knn, 10, COTree_t<10>, 0) 219 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_HT}}); 220 | BENCH(knn, 10, BHLTree_t<10>, 0) 221 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_HT}}); 222 | BENCH(knn3, 10, 0)->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_HT}}); 223 | 224 | BENCH(knn, 16, COTree_t<16>, 0) 225 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_CHEM}}); 226 | BENCH(knn, 16, BHLTree_t<16>, 0) 227 | ->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_CHEM}}); 228 | BENCH(knn3, 16, 0)->ArgsProduct({{10'000'000}, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, {DS_CHEM}}); 229 | -------------------------------------------------------------------------------- /benchmark/datasets: -------------------------------------------------------------------------------- 1 | ../../../dataGenerator -------------------------------------------------------------------------------- /benchmark/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCHMARK_UTILS_H 2 | #define BENCHMARK_UTILS_H 3 | 4 | #include "parlay/random.h" 5 | #include 6 | 7 | // --- Taken from parlaylib --- 8 | // Use this macro to avoid accidentally timing the destructors 9 | // of the output produced by algorithms that return data 10 | // 11 | // The expression e is evaluated as if written in the context 12 | // auto result_ = (e); 13 | // 14 | #define RUN_AND_CLEAR(e) \ 15 | { \ 16 | auto result_ = (e); \ 17 | state.PauseTiming(); \ 18 | } \ 19 | state.ResumeTiming(); 20 | 21 | // Define the benchmarks 22 | #define BENCH(NAME, ...) \ 23 | BENCHMARK_TEMPLATE(bench_##NAME, ##__VA_ARGS__)->UseRealTime()->Unit(benchmark::kMillisecond) 24 | 25 | // --- Data loading --- 26 | template 27 | void AddNoise(parlay::sequence>& points) { 28 | std::default_random_engine generator; 29 | std::uniform_real_distribution distribution(0.0, 1e-6); 30 | 31 | for (size_t i = 0; i < points.size(); i++) { 32 | for (int d = 0; d < dim; d++) { 33 | points[i][d] += distribution(generator); 34 | } 35 | } 36 | } 37 | 38 | template 39 | auto LoadFile(const char* filePath) { 40 | [[maybe_unused]] auto read_dim = readDimensionFromFile(filePath); 41 | assert(read_dim == dim); 42 | auto ret = readPointsFromFile>(filePath); 43 | if (add_noise) AddNoise(ret); 44 | return ret; 45 | } 46 | 47 | auto UniformSphere2D_1K() { return LoadFile<2>("datasets/2d-UniformInSphere-1k.pbbs"); } 48 | auto UniformSphere2D_10K() { return LoadFile<2>("datasets/2d-UniformInSphere-10K.pbbs"); } 49 | auto UniformSphere2D_1M() { return LoadFile<2>("datasets/2d-UniformInSphere-1M.pbbs"); } 50 | auto UniformSphere2D_10M() { return LoadFile<2>("datasets/2d-UniformInSphere-10M.pbbs"); } 51 | auto VisualVar5D_100K() { return LoadFile<5>("datasets/5D_VisualVar_100K.pbbs"); } 52 | auto VisualVar5D_1M() { return LoadFile<5>("datasets/5D_VisualVar_1M.pbbs"); } 53 | 54 | // Benchmark Datasets 55 | 56 | auto UniformFill2D_10M() { return LoadFile<2>("datasets/2D_UniformFill_10M.pbbs"); } 57 | auto UniformFill5D_10M() { return LoadFile<5>("datasets/5D_UniformFill_10M.pbbs"); } 58 | auto UniformFill7D_10M() { return LoadFile<7>("datasets/7D_UniformFill_10M.pbbs"); } 59 | auto VisualVar2D_10M() { return LoadFile<2, true>("datasets/2D_VisualVar_10M.pbbs"); } 60 | auto VisualVar5D_10M() { return LoadFile<5, true>("datasets/5D_VisualVar_10M.pbbs"); } 61 | auto VisualVar7D_10M() { return LoadFile<7, true>("datasets/7D_VisualVar_10M.pbbs"); } 62 | auto GeoLife3D_24M() { return LoadFile<3, true>("datasets/3D_GeoLife_24M.pbbs"); } 63 | auto HouseHold7D_2M() { return LoadFile<7, true>("datasets/7D_HouseHold_2M.pbbs"); } 64 | auto HT10D_1M() { return LoadFile<10, true>("datasets/HT.pbbs"); } 65 | auto CHEM16D_4M() { return LoadFile<16, true>("datasets/CHEM.pbbs"); } 66 | 67 | enum DSType { 68 | DS_UNIFORM_FILL, // 0 69 | DS_UNIFORM_SPHERE, // 1 70 | DS_VISUAL_VAR, // 2 71 | DS_GEO_LIFE, // 3 72 | DS_HOUSE_HOLD, // 4 73 | DS_HT, // 5 74 | DS_CHEM // 6 75 | }; 76 | template 77 | auto BenchmarkDS(__attribute__((unused)) int size, 78 | __attribute__((unused)) DSType ds_type, 79 | bool shuffle = true) { 80 | std::stringstream ss; 81 | ss << "Invalid dim=" << dim << " to BenchmarkDS"; 82 | throw std::runtime_error(ss.str()); 83 | } 84 | 85 | template <> 86 | auto BenchmarkDS<2>(int size, DSType ds_type, bool shuffle) { 87 | parlay::sequence> ret; 88 | switch (ds_type) { 89 | case DS_UNIFORM_FILL: { 90 | ret = UniformFill2D_10M(); 91 | break; 92 | } 93 | case DS_UNIFORM_SPHERE: { 94 | if (size == 1'000) 95 | ret = UniformSphere2D_1K(); 96 | else if (size == 10'000) 97 | ret = UniformSphere2D_10K(); 98 | else if (size == 1'000'000) 99 | ret = UniformSphere2D_1M(); 100 | else if (size == 10'000'000) 101 | ret = UniformSphere2D_10M(); 102 | else 103 | throw std::runtime_error("Invalid size to BenchmarkDS<2>(DS_UNIFORM_SPHERE)"); 104 | break; 105 | } 106 | case DS_VISUAL_VAR: { 107 | ret = VisualVar2D_10M(); 108 | break; 109 | } 110 | default: 111 | throw std::runtime_error("Invalid type to BenchmarkDS<2>"); 112 | } 113 | 114 | if (shuffle) 115 | return random_shuffle(ret); 116 | else 117 | return ret; 118 | } 119 | 120 | template <> 121 | auto BenchmarkDS<3>(__attribute__((unused)) int size, DSType ds_type, bool shuffle) { 122 | parlay::sequence> ret; 123 | switch (ds_type) { 124 | case DS_GEO_LIFE: { 125 | ret = GeoLife3D_24M(); 126 | break; 127 | } 128 | default: 129 | throw std::runtime_error("Invalid type to BenchmarkDS<3>"); 130 | } 131 | 132 | if (shuffle) 133 | return random_shuffle(ret); 134 | else 135 | return ret; 136 | } 137 | 138 | template <> 139 | auto BenchmarkDS<5>(int size, DSType ds_type, bool shuffle) { 140 | parlay::sequence> ret; 141 | switch (ds_type) { 142 | case DS_UNIFORM_FILL: { 143 | ret = UniformFill5D_10M(); 144 | break; 145 | } 146 | case DS_VISUAL_VAR: { 147 | if (size == 100'000) 148 | ret = VisualVar5D_100K(); 149 | else if (size == 1'000'000) 150 | ret = VisualVar5D_1M(); 151 | else if (size == 10'000'000) 152 | ret = VisualVar5D_10M(); 153 | else 154 | throw std::runtime_error("Invalid size to BenchmarkDS<5>(DS_VISUAL_VAR)"); 155 | break; 156 | } 157 | default: 158 | throw std::runtime_error("Invalid type to BenchmarkDS<5>"); 159 | } 160 | 161 | if (shuffle) 162 | return random_shuffle(ret); 163 | else 164 | return ret; 165 | } 166 | 167 | template <> 168 | auto BenchmarkDS<7>(__attribute__((unused)) int size, DSType ds_type, bool shuffle) { 169 | parlay::sequence> ret; 170 | switch (ds_type) { 171 | case DS_UNIFORM_FILL: { 172 | ret = UniformFill7D_10M(); 173 | break; 174 | } 175 | case DS_VISUAL_VAR: { 176 | ret = VisualVar7D_10M(); 177 | break; 178 | } 179 | case DS_HOUSE_HOLD: { 180 | ret = HouseHold7D_2M(); 181 | break; 182 | } 183 | default: 184 | throw std::runtime_error("Invalid type to BenchmarkDS<7>"); 185 | } 186 | 187 | if (shuffle) 188 | return random_shuffle(ret); 189 | else 190 | return ret; 191 | } 192 | 193 | template <> 194 | auto BenchmarkDS<10>(__attribute__((unused)) int size, DSType ds_type, bool shuffle) { 195 | parlay::sequence> ret; 196 | switch (ds_type) { 197 | case DS_HT: { 198 | ret = HT10D_1M(); 199 | break; 200 | } 201 | default: 202 | throw std::runtime_error("Invalid type to BenchmarkDS<10>"); 203 | } 204 | 205 | if (shuffle) 206 | return random_shuffle(ret); 207 | else 208 | return ret; 209 | } 210 | 211 | template <> 212 | auto BenchmarkDS<16>(__attribute__((unused)) int size, DSType ds_type, bool shuffle) { 213 | parlay::sequence> ret; 214 | switch (ds_type) { 215 | case DS_CHEM: { 216 | ret = CHEM16D_4M(); 217 | break; 218 | } 219 | default: 220 | throw std::runtime_error("Invalid type to BenchmarkDS<16>"); 221 | } 222 | 223 | if (shuffle) 224 | return random_shuffle(ret); 225 | else 226 | return ret; 227 | } 228 | 229 | // types 230 | constexpr bool parallel = true; 231 | constexpr bool coarsen = true; 232 | 233 | template 234 | using COTree_t = CO_KdTree, parallel, coarsen>; 235 | 236 | template 237 | using BHLTree_t = BHL_KdTree, parallel, coarsen>; 238 | 239 | constexpr int NUM_TREES = 21; 240 | constexpr int BUFFER_LOG2_SIZE = 10; 241 | template 242 | using LogTree_t = LogTree, parallel, coarsen>; 243 | 244 | #endif // BENCHMARK_UTILS_H 245 | -------------------------------------------------------------------------------- /executable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | set(CMAKE_CXX_STANDARD 17) 3 | 4 | file(GLOB SRCS *.cpp) 5 | 6 | # tree time 7 | add_executable(treeTime treeTime.cpp) 8 | target_link_libraries(treeTime PRIVATE 9 | kdtree 10 | external) 11 | 12 | # test parlay functions 13 | add_executable(parlayTest parlayTest.cpp) 14 | target_link_libraries(parlayTest PRIVATE 15 | kdtree 16 | external) 17 | -------------------------------------------------------------------------------- /executable/parlayTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "parlay/parallel.h" 5 | #include "parlay/sequence.h" 6 | #include "parlay/primitives.h" 7 | 8 | #include "common/geometry.h" 9 | #include "common/geometryIO.h" 10 | 11 | #include "../include/kdtree/shared/utils.h" 12 | #include "../include/kdtree/shared/macro.h" 13 | 14 | void testScan() { 15 | parlay::sequence p; 16 | for (int i = 0; i < 10; i++) 17 | p.push_back(i); 18 | 19 | auto [res, sum] = parlay::scan(p); 20 | 21 | for (const auto& r : res) 22 | std::cout << r << " "; 23 | std::cout << "\nsum = " << sum << std::endl; 24 | 25 | // another test 26 | auto res1 = parlay::scan_inclusive(p); 27 | for (const auto& r : res1) 28 | std::cout << r << " "; 29 | } 30 | 31 | void testLoop(int argc, const char** argv) { 32 | if (argc != 2) throw std::runtime_error("need to pass file name!"); 33 | const char* test_file = argv[1]; 34 | 35 | constexpr int dim = 2; 36 | int check_dim = readDimensionFromFile(test_file); 37 | if (check_dim != dim) throw std::runtime_error("Invalid input file!"); 38 | auto P = readPointsFromFile>(test_file); 39 | auto P_slice = parlay::slice(P.begin(), P.end()); 40 | 41 | parlay::sequence> Q(P.size()); 42 | auto Q_slice = parlay::slice(Q.begin(), Q.end()); 43 | 44 | timer t; 45 | parlay::parallel_for( 46 | 0, P_slice.size(), [Q_slice, P_slice](size_t i) { Q_slice[i] = P_slice[i]; }); 47 | std::cout << t.get_next() << std::endl; 48 | } 49 | 50 | static parlay::sequence> PARLAY_2D_TEST_POINTS(size_t num_points) { 51 | constexpr int dim = 2; 52 | std::vector> point_vec(num_points); 53 | for (size_t i = 0; i < num_points; i++) 54 | point_vec[i] = point({(double)i, (double)i}); 55 | parlay::sequence> points(point_vec.begin(), point_vec.end()); 56 | return points; 57 | } 58 | 59 | void testSpatial(int argc, const char** argv) { 60 | size_t size; 61 | if (argc == 1) 62 | size = 8; 63 | else if (argc == 2) 64 | size = std::stoul(argv[1]); 65 | else 66 | throw std::runtime_error("invalid input"); 67 | 68 | auto points = PARLAY_2D_TEST_POINTS(size); 69 | parlay::sequence flags(points.size()); 70 | size_t split_pt; 71 | auto median = parallelSpatialPartition( 72 | points.cut(0, points.size()), flags.cut(0, flags.size()), 0, split_pt); 73 | 74 | std::cout << "(median, split_pt) = (" << median << ", " << split_pt << ")" << std::endl; 75 | } 76 | 77 | int main(int argc, const char** argv) { print_config(); } 78 | -------------------------------------------------------------------------------- /executable/treeTime.cpp: -------------------------------------------------------------------------------- 1 | // This code is part of the Problem Based Benchmark Suite (PBBS) 2 | // Copyright (c) 2011 Guy Blelloch and the PBBS team 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a 5 | // copy of this software and associated documentation files (the 6 | // "Software"), to deal in the Software without restriction, including 7 | // without limitation the rights (to use, copy, modify, merge, publish, 8 | // distribute, sublicense, and/or sell copies of the Software, and to 9 | // permit persons to whom the Software is furnished to do so, subject to 10 | // the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included 13 | // in all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #include 24 | #include 25 | #include "parlay/parallel.h" 26 | #include "common/get_time.h" 27 | #include "common/geometry.h" 28 | #include "common/geometryIO.h" 29 | #include "common/parse_command_line.h" 30 | 31 | #include "kdtree/cache-oblivious/cokdtree.h" 32 | #include "kdtree/binary-heap-layout/bhlkdtree.h" 33 | #include "kdtree/log-tree/logtree.h" 34 | #include "kdtree/shared/dual.h" 35 | 36 | using namespace benchIO; 37 | 38 | using coord = double; 39 | 40 | enum TestType { 41 | INVALID = 0, 42 | CONSTRUCTION, 43 | RANGE_QUERY, 44 | CONTAINS, 45 | KNN, 46 | KNN2, 47 | KNN3, 48 | DUAL_KNN, 49 | DELETE, 50 | INSERT, 51 | INSERT_DELETE 52 | }; 53 | bool is_knn(const TestType& t) { 54 | return (t == KNN) || (t == KNN2) || (t == KNN3) || (t == DUAL_KNN); 55 | } 56 | 57 | static std::ostream& operator<<(std::ostream& os, const TestType& t) { 58 | switch (t) { 59 | case INVALID: 60 | os << "INVALID"; 61 | break; 62 | case CONSTRUCTION: 63 | os << "CONSTRUCTION"; 64 | break; 65 | case RANGE_QUERY: 66 | os << "RANGE_QUERY"; 67 | break; 68 | case CONTAINS: 69 | os << "CONTAINS"; 70 | break; 71 | case KNN: 72 | os << "KNN"; 73 | break; 74 | case KNN2: 75 | os << "KNN2"; 76 | break; 77 | case KNN3: 78 | os << "KNN3"; 79 | break; 80 | case DUAL_KNN: 81 | os << "DUAL_KNN"; 82 | break; 83 | case DELETE: 84 | os << "DELETE"; 85 | break; 86 | case INSERT: 87 | os << "INSERT"; 88 | break; 89 | case INSERT_DELETE: 90 | os << "INSERT + DELETE"; 91 | break; 92 | } 93 | return os; 94 | } 95 | 96 | struct TestOptions { 97 | bool run_serial; 98 | bool run_parallel; 99 | bool run_co; 100 | bool run_bhl; 101 | bool run_log; 102 | int rounds; 103 | int k; // for knn 104 | int k_type; // for knn 105 | int percentage; // for delete/construction 106 | TestType type; 107 | const char* out_file; 108 | 109 | TestOptions() 110 | : run_serial(false), 111 | run_parallel(false), 112 | run_co(false), 113 | run_bhl(false), 114 | run_log(false), 115 | rounds(0), 116 | k(3), 117 | k_type(0), 118 | percentage(-1), 119 | type(INVALID), 120 | out_file(nullptr) {} 121 | }; 122 | 123 | template 124 | void timeConstruction(parlay::sequence> const& P, int rounds, int percentage) { 125 | // P is our local copy, we can move into tree 126 | if (percentage == -1) percentage = 100; // default 127 | auto P_slice = P.cut(0, (P.size() * percentage) / 100); 128 | // auto construct_size = (P.size() * percentage) / 100; 129 | // parlay::sequence> P_construct; 130 | // P_construct.assign(P.begin(), P.begin() + construct_size); 131 | timer t; 132 | for (int i = 0; i < rounds; ++i) { 133 | t.start(); 134 | Tree tree(P_slice); 135 | auto build_time = t.get_next(); 136 | // std::cout << " -> build-time = " << build_time << std::endl; 137 | if (i > 0) std::cout << ", "; 138 | std::cout << build_time; 139 | } 140 | t.stop(); 141 | } 142 | 143 | template 144 | void timeContainsQuery(parlay::sequence> const& P, int rounds) { 145 | constexpr int rep = 10000; 146 | double x[dim]; 147 | point pnot[rep]; 148 | 149 | for (int j = 0; j < rep; j++) { 150 | for (int i = 0; i < dim; i++) { 151 | x[i] = i; 152 | } 153 | pnot[j] = point(x); 154 | } 155 | 156 | timer t; 157 | for (int i = 0; i < rounds; ++i) { 158 | if (i > 0) std::cout << ", "; 159 | Tree tree(P); 160 | 161 | t.start(); 162 | for (int j = 0; j < rep; j++) { 163 | tree.contains(pnot[j]); 164 | } 165 | auto query_time_1 = t.get_next(); 166 | // std::cout << " -> " << rep << "x query-time (-) = " << query_time_1 << std::endl; 167 | std::cout << "[" << query_time_1 << ", "; 168 | t.reset(); 169 | 170 | t.start(); 171 | for (int j = 0; j < rep; j++) { 172 | tree.contains(P[j]); 173 | } 174 | auto query_time_2 = t.get_next(); 175 | // std::cout << " -> " << rep << "x query-time (+) = " << query_time_2 << std::endl; 176 | std::cout << query_time_2 << "]"; 177 | } 178 | t.stop(); 179 | } 180 | 181 | template 182 | void timeRangeQuery(parlay::sequence> const& P, int rounds) { 183 | constexpr int rep = 10; 184 | 185 | // compute full bounding box 186 | point pMin, pMax; 187 | pMin = P[0]; 188 | pMax = P[0]; 189 | for (const auto& pt : P) { 190 | pMin.minCoords(pt); 191 | pMax.maxCoords(pt); 192 | } 193 | /*auto printPoint = [](const point& p) { 194 | std::stringstream ss; 195 | ss << "("; 196 | for (int i = 0; i < dim; i++) { 197 | if (i > 0) ss << ", "; 198 | ss << p.coordinate(i); 199 | } 200 | ss << ")"; 201 | return ss.str(); 202 | }; 203 | std::cout << "Min: " << printPoint(pMin) << std::endl; 204 | std::cout << "Max: " << printPoint(pMax) << std::endl;*/ 205 | 206 | // scale in by 10x on each dimension -> 1% for 2d 207 | double x[dim]; 208 | for (int i = 0; i < dim; i++) 209 | x[i] = pMin[i] / 10; 210 | auto qMin = point(x); 211 | for (int i = 0; i < dim; i++) 212 | x[i] = pMax[i] / 10; 213 | auto qMax = point(x); 214 | 215 | timer t; 216 | for (int i = 0; i < rounds; ++i) { 217 | Tree tree(P); 218 | 219 | parlay::sequence> p; 220 | t.start(); 221 | for (int j = 0; j < rep; j++) { 222 | p = tree.orthogonalQuery(qMin, qMax); 223 | } 224 | auto time = t.get_next(); 225 | // std::cout << " -> " << rep << "x query-time (" << p.size() << " points) = " <