├── .gitignore ├── COPYING.md ├── README.md ├── apply_style.sh ├── benchmark ├── Alloc_Dealloc_Time.cpp ├── Alloc_Time.cpp ├── Alloc_Time_CT.cpp ├── Basic_Tests.h ├── BoostAtomicSharedPtrAdaptor.h ├── BoostSharedPtrAdaptor.h ├── Concurrent_BST.cpp ├── Concurrent_BTree.cpp ├── Concurrent_HashMap.cpp ├── Concurrent_Struct_CRUD_Tests.h ├── Concurrent_Struct_Helpers.h ├── Concurrent_Struct_Insert_Tests.h ├── Concurrent_Struct_Read_Tests.h ├── Concurrent_Struct_Remove_Tests.h ├── Datasets.cpp ├── Datasets.h ├── Dealloc_Time.cpp ├── Pointer_Set.cpp ├── RawPtrAdaptor.h ├── STDSharedPtrAdaptor.h ├── Single_Contention.cpp ├── Slop_Size.cpp ├── Static_Tree_Router_Test.cpp ├── Timing_Test.cpp ├── cds │ ├── AStandardHashMap.h │ ├── BST.h │ ├── BTree.h │ ├── Comparators.h │ ├── HashFunctions.h │ ├── HashMapCPC.h │ ├── IComparable.h │ ├── IHashable.h │ ├── RStandardHashMap.h │ ├── binarySearch.h │ └── hashFunctions.h └── common.h ├── build ├── .gitignore ├── benchmark │ └── CMakeLists.txt ├── frc │ └── CMakeLists.txt └── test │ └── CMakeLists.txt ├── cmake ├── CompilerOptions.cmake ├── EL.cmake ├── FRCLink.cmake ├── GetFileHelpers.cmake ├── Nuke.cmake ├── OnlyFindStaticLibraries.cmake └── ProcessDependencies.cmake ├── lib ├── BoostInstall.cmake ├── BoostLink.cmake ├── GoogleTestInstall.cmake └── GoogleTestLink.cmake ├── src ├── frc │ ├── AtomicPointer.h │ ├── PrivatePointer.h │ ├── SharedPointer.h │ ├── detail │ │ ├── ArrayHeader.h │ │ ├── DestructorMap.h │ │ ├── FRCConstants.h │ │ ├── FRCManager.cpp │ │ ├── FRCManager.h │ │ ├── HelpRouter.cpp │ │ ├── HelpRouter.h │ │ ├── ObjectHeader.h │ │ ├── PinSet.cpp │ │ ├── PinSet.h │ │ ├── ThreadData.cpp │ │ └── ThreadData.h │ └── frc.h ├── synchronization │ ├── MutexSpin.h │ ├── Relaxer.h │ ├── Spinner.h │ ├── StaticTreeRouter.cpp │ └── StaticTreeRouter.h └── util │ ├── DebugPrintf.cpp │ ├── DebugPrintf.h │ ├── Exception.cpp │ ├── Exception.h │ ├── FastRNG.cpp │ ├── FastRNG.h │ ├── Isolate.h │ ├── atomic.h │ ├── bitTricks.h │ ├── defs.hpp │ ├── directives.h │ ├── getticks.h │ ├── platformSpecific.h │ ├── thread.cpp │ ├── thread.h │ ├── tls.h │ ├── tlsGCC.h │ ├── tlsWindowsGCCx64.h │ ├── toStringStream.h │ ├── type_name.h │ ├── types.h │ └── util.h └── test ├── frc └── FRC_test.cpp ├── precompiled.h ├── synchronization ├── MutexSpin_tests.cpp ├── MutexTestModule.h └── std_Mutex_tests.cpp └── util ├── ExceptionTests.cpp ├── bitTricks_tests.cpp └── thread_tests.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .kdev4 2 | .idea 3 | *.pyc 4 | *.swp 5 | *.o 6 | *.exe 7 | *.class 8 | *.gch 9 | *.gch.debug 10 | *.gch.release 11 | .directory 12 | *.d 13 | *#*# 14 | *~ 15 | 16 | # Do not include pdfs 17 | *.png 18 | *.pdf 19 | 20 | # meld merge files 21 | *.orig 22 | *_BACKUP_* 23 | *_BASE_* 24 | *_LOCAL_* 25 | *_REMOTE_* 26 | 27 | __pycache__ 28 | nbproject 29 | compile_commands.json 30 | */lockfile 31 | default.tag 32 | lockfile 33 | log 34 | external_libs 35 | 36 | # Do not include source/build of external libraries 37 | /lib/Release 38 | /lib/Debug 39 | /lib/src 40 | /lib/tmp 41 | 42 | # Do not include files generated by CMake 43 | Makefile 44 | CMakeCache.txt 45 | CMakeFiles 46 | cmake_install.cmake 47 | 48 | # Do not include built binaries 49 | bin 50 | benchmark/data 51 | -------------------------------------------------------------------------------- /COPYING.md: -------------------------------------------------------------------------------- 1 | Copyright 2018 Terrain Data, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Fast Reference Counter (FRC) 2 | 3 | (C) 2017, 2018 Terrain Data, Inc. 4 | 5 | ## Introduction 6 | 7 | FRC is a high-performance reference counting library for C++. It provides 8 | smart pointer types with performance that greatly exceeds that of 9 | `std::shared_ptr` and `boost::atomic_shared_ptr`, for example; in 10 | particular, FRC's reference-counted pointer types excel in concurrent 11 | scenarios (such as concurrent data structures). A research paper describing 12 | FRC in detail is linked at the bottom of this file. 13 | 14 | ## Organization 15 | 16 | The repository consists of three main components: 17 | 18 | * The FRC library 19 | * Unit tests for the FRC library and supporting components 20 | * Benchmarks for the FRC library 21 | 22 | Source code for the tests is located under the `test` folder, and source code 23 | for the benchmarks is located under the `benchmark` folder. Source code for 24 | the FRC library is located under the `src` directory. 25 | 26 | All build files (including binary output, CMake build scripts, Makefiles, etc.) 27 | are located under the `build` directory. Each of the components of the 28 | repository has its own subdirectory and associated `CMakeLists.txt` under the 29 | build directory. 30 | 31 | The root-level `cmake` directory contains CMake helper routines, including the 32 | common compiler flags used for compiling the projects. 33 | 34 | The root-level `lib` directory contains scripts (and, when the FRC library is 35 | built, the corresponding headers/libraries) for downloading and building 36 | dependent libraries, such as Boost and Google Test (the latter being used for 37 | managing tests and benchmarks). 38 | 39 | ## Dependencies 40 | 41 | FRC automatically downloads and builds certain dependencies like Boost. 42 | However, certain other dependencies may need to be installed. For example, 43 | in order to run `apply_style.sh`, you should first install the following 44 | dependencies (written here as a one-line command for Debian-like operating 45 | systems): 46 | ```bash 47 | sudo apt-get install astyle 48 | ``` 49 | 50 | ## Contributing 51 | 52 | We welcome contributions to the FRC project. Any new commits should be sure to 53 | adhere to our code style; please run `./apply_style.sh` each time you are about 54 | to make a commit in order to automatically enforce our code style. 55 | 56 | ## License 57 | 58 | Please see the included [COPYING.md](COPYING.md). 59 | 60 | ## Using in a Research Project 61 | 62 | For details on FRC, download our research paper for free 63 | [here](https://dl.acm.org/doi/10.1145/3299706.3210569?cid=99659276755). 64 | If you use FRC in a research project, please cite our paper (citation below), 65 | and please let us know about your paper! 66 | 67 | > Charles Tripp, David Hyde, and Benjamin Grossman-Ponemon. 2018. 68 | > FRC: A High-Performance Concurrent Parallel Deferred Reference Counter for C++. 69 | > In Proceedings of the 2018 ACM SIGPLAN International Symposium on Memory Management 70 | > (ISMM '18). ACM, New York, NY, USA, 14-28. 71 | > https://doi.org/10.1145/3210563.3210569 72 | 73 | -------------------------------------------------------------------------------- /apply_style.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # File: apply_style.sh 4 | # Copyright 2017 Terrain Data, Inc. 5 | # 6 | # This file is part of FRC, a fast reference counting library for C++ 7 | # (see ). 8 | # 9 | # FRC is distributed under the MIT License, which is found in 10 | # COPYING.md in the repository. 11 | # 12 | # You should have received a copy of the MIT License 13 | # along with FRC. If not, see . 14 | 15 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 16 | cd $DIR 17 | 18 | astyle=astyle 19 | 20 | force= 21 | 22 | if [ "$1" == "-f" ]; 23 | then 24 | force=1 25 | shift 26 | fi 27 | 28 | # override path to astyle 29 | if [ "$1" == "--astyle" ]; 30 | then 31 | astyle=$2 32 | shift 33 | shift 34 | fi 35 | 36 | extraopts= 37 | if [ "$1" == "--dry-run" ]; 38 | then 39 | extraopts="$extraopts --dry-run" 40 | shift 41 | fi 42 | 43 | # Use astyle to format C++ code 44 | $astyle -r -X -Q -Z -n --formatted --ignore-exclude-errors-x --lineend=linux --style=allman --indent=spaces=4 --indent-switches --indent-labels --indent-col1-comments --pad-oper --unpad-paren --align-pointer=type --align-reference=type --keep-one-line-statements --max-code-length=95 'src/*.cpp' 'src/*.h' 'test/*.cpp' 'test/*.h' 'benchmark/*.cpp' 'benchmark/*.h' $extraopts 45 | 46 | -------------------------------------------------------------------------------- /benchmark/Alloc_Time_CT.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Alloc_Time_CT.cpp 3 | * Copyright 2017, 2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | using namespace std; 33 | using namespace std::chrono; 34 | using namespace boost; 35 | 36 | using namespace terrain; 37 | 38 | using namespace terrain::frc; 39 | 40 | namespace terrain 41 | { 42 | namespace benchmarks 43 | { 44 | namespace alloc_time 45 | { 46 | static constexpr sz max_values = 1e6; 47 | static constexpr sz iter_inc = 1e5; 48 | static constexpr sz num_trials = 1000; 49 | static constexpr sz num_threads = 24; 50 | static constexpr sz num_values = 10e3; 51 | using Type = lng; 52 | 53 | template 54 | static void alloc_test(string name, Function func) 55 | { 56 | vector times(num_threads); 57 | vector threads; 58 | 59 | //for(sz num_values = iter_inc; num_values <= max_values; num_values += iter_inc) 60 | 61 | cout << "num_values = " << num_values << endl; 62 | for(sz t = 0; t < num_threads; ++t) 63 | { 64 | threads.emplace_back( 65 | [&](sz t2) 66 | { 67 | bindToProcessor(t2); 68 | FRCToken t; 69 | high_resolution_clock::time_point tic; 70 | high_resolution_clock::time_point toc; 71 | 72 | tic = high_resolution_clock::now(); 73 | for(sz trial = 0; trial < num_trials; ++trial) 74 | { 75 | func(num_values); 76 | }; 77 | toc = high_resolution_clock::now(); 78 | times[t2] = std::chrono::duration_cast> 79 | (toc - tic).count(); 80 | }, t); 81 | } 82 | 83 | for(auto& t : threads) 84 | t.join(); 85 | 86 | double time = 0; 87 | for(sz t = 0; t < num_threads; ++t) 88 | { 89 | time += times[t]; 90 | } 91 | 92 | cout << name << ": " << time << endl; 93 | 94 | ofstream ofile("./alloc_time.txt", ios::app); 95 | ofile << name << ",\t"; 96 | ofile << time; 97 | ofile << endl; 98 | } 99 | 100 | TEST(FRC_Basic, ct_alloc_time_malloc) 101 | { 102 | alloc_test("new and delete", [](sz num_values) 103 | { 104 | std::unique_ptr values(new Type *[num_values]); 105 | for(sz i = 0; i < num_values; ++i) 106 | { 107 | values[i] = new Type(5); 108 | } 109 | 110 | for(sz i = 0; i < num_values; ++i) 111 | { 112 | delete values[i]; 113 | } 114 | }); 115 | } 116 | 117 | TEST(FRC_Basic, ct_alloc_time_std) 118 | { 119 | alloc_test("std::shared_ptr with std::make_shared", []( 120 | sz num_values) 121 | { 122 | std::unique_ptr[]> values(new std::shared_ptr[num_values]); 123 | for(sz i = 0; i < num_values; ++i) 124 | { 125 | values[i] = std::make_shared(5); 126 | } 127 | }); 128 | } 129 | 130 | //TEST(FRC_Basic, ct_alloc_time_frc_s) 131 | //{ 132 | // alloc_test("AtomicPointer::AtomicPointer", [](sz num_values) 133 | // { 134 | // unique_ptr[]> values(new AtomicPointer[num_values]); 135 | // for(sz i = 0; i < num_values; ++i) 136 | // { 137 | // values[i] = std::make_shared(5); 138 | // } 139 | // 140 | // for(sz i = 0; i < num_values; ++i) 141 | // { 142 | // AtomicPointer ptr(5); 143 | // } 144 | // }); 145 | //} 146 | 147 | TEST(FRC_Basic, ct_alloc_time_frc_s_makeProtected) 148 | { 149 | alloc_test("AtomicPointer::make", [](sz num_values) 150 | { 151 | std::unique_ptr[]> values(new AtomicPointer[num_values]); 152 | for(sz i = 0; i < num_values; ++i) 153 | { 154 | values[i].make(5); 155 | } 156 | }); 157 | } 158 | 159 | //TEST(FRC_Basic, ct_alloc_time_frc_p) 160 | //{ 161 | // alloc_test("PrivatePointer::PrivatePointer()", [](sz num_values) 162 | // { 163 | // for(sz i = 0; i < num_values; ++i) 164 | // { 165 | // PrivatePointer ptr(lng(5)); 166 | // } 167 | // }); 168 | //} 169 | 170 | } /* namespace alloc_time */ 171 | } /* namespace benchmarks */ 172 | } /* namespace terrain */ 173 | 174 | -------------------------------------------------------------------------------- /benchmark/Basic_Tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Basic_Tests.h 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace terrain 21 | { 22 | namespace benchmarks 23 | { 24 | namespace basic 25 | { 26 | static constexpr lng maxValues = 1e5; 27 | static constexpr lng incValues = 1e4; 28 | static constexpr lng numTrials = 3; 29 | static constexpr lng maxThreads = 32; 30 | static constexpr lng incThreads = 1; 31 | using Type = lng; 32 | 33 | template 34 | static void test(string testName, TestBody body, TestType testMode, bool useThreadFRC = false, 35 | bool useGlobalFRC = false, bool printSizes = false) 36 | { 37 | frc::FRCToken token; 38 | 39 | std::vector threads; 40 | std::vector threadTimes(maxThreads, 0.); 41 | std::vector sizes; 42 | std::vector times; 43 | 44 | lng incIters, maxIters; 45 | lng numThreads, numValues; 46 | if(testMode == TestType::workload) 47 | { 48 | // Iterate over values 49 | incIters = incValues; 50 | maxIters = maxValues; 51 | numThreads = maxThreads; 52 | } 53 | else 54 | { 55 | // Iterate over threads 56 | incIters = incThreads; 57 | maxIters = maxThreads; 58 | numValues = maxValues; 59 | } 60 | 61 | for(lng numIters = incIters; numIters <= maxIters; numIters += incIters) 62 | { 63 | sizes.push_back(numIters); 64 | if(testMode == TestType::workload) 65 | numValues = numIters; 66 | else 67 | numThreads = numIters; 68 | std::cout << "numValues = " << numValues << "\tnumThreads = " << numThreads << std::endl; 69 | 70 | boost::barrier threadBarrier(numThreads); 71 | 72 | for(lng trial = 0; trial < numTrials; ++trial) 73 | { 74 | threads.clear(); 75 | for(lng t = 0; t < numThreads; ++t) 76 | { 77 | threads.emplace_back([&](sz t2) 78 | { 79 | bindToProcessor(t2); 80 | frc::FRCToken token; 81 | threadBarrier.wait(); // Get all threads at the ready then go 82 | 83 | double localTime = 0.; 84 | body(numValues, localTime); 85 | threadTimes[t2] = localTime; 86 | }, t); 87 | } 88 | for(auto& t : threads) 89 | t.join(); 90 | } 91 | times.push_back(accumulate(threadTimes.begin(), threadTimes.end(), 92 | 0.) / (numValues * numThreads)); 93 | } 94 | 95 | std::ofstream ofile; 96 | if(printSizes) 97 | { 98 | ofile.open("./" + testName + ".txt"); 99 | ofile << sizes[0]; 100 | for(sz i = 1; i < sizes.size(); ++i) 101 | ofile << "," << sizes[i]; 102 | ofile << std::endl; 103 | } 104 | else 105 | ofile.open("./" + testName + ".txt", std::ios::app); 106 | ofile << std::scientific << std::setprecision(10) << times[0]; 107 | for(sz i = 1; i < sizes.size(); ++i) 108 | ofile << "," << times[i]; 109 | ofile << std::endl; 110 | } 111 | 112 | } /* namespace basic */ 113 | } /* namespace benchmarks */ 114 | } /* namespace terrain */ 115 | -------------------------------------------------------------------------------- /benchmark/BoostAtomicSharedPtrAdaptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: BoostAtomicSharedPtrAdaptor.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "BoostSharedPtrAdaptor.h" 23 | 24 | namespace terrain 25 | { 26 | namespace frc 27 | { 28 | 29 | /** 30 | * Adaptor class that delegates to a boost::atomic_shared_ptr 31 | */ 32 | template 33 | class BoostAtomicSharedPtrAdaptor 34 | { 35 | template 36 | friend class BoostAtomicSharedPtrAdaptor; 37 | 38 | private: 39 | boost::atomic_shared_ptr delegate; 40 | 41 | public: 42 | 43 | BoostAtomicSharedPtrAdaptor() 44 | { 45 | ; 46 | } 47 | 48 | BoostAtomicSharedPtrAdaptor(BoostAtomicSharedPtrAdaptor&& that) 49 | { 50 | delegate.store(that.delegate.load()); 51 | that.delegate.store(nullptr); 52 | }; 53 | 54 | BoostAtomicSharedPtrAdaptor(BoostAtomicSharedPtrAdaptor const& that) 55 | { 56 | delegate.store(that.delegate.load()); 57 | } 58 | 59 | template 60 | BoostAtomicSharedPtrAdaptor(BoostAtomicSharedPtrAdaptor const& that) 61 | { 62 | boost::shared_ptr tmp = boost::static_pointer_cast(that.delegate.load()); 63 | delegate.store(tmp); 64 | } 65 | 66 | template 67 | BoostAtomicSharedPtrAdaptor(BoostAtomicSharedPtrAdaptor& that) : 68 | BoostAtomicSharedPtrAdaptor((BoostAtomicSharedPtrAdaptor const&)that) 69 | { 70 | ; 71 | } 72 | 73 | template 74 | explicit BoostAtomicSharedPtrAdaptor(Args&& ... args) 75 | { 76 | delegate.store(boost::make_shared(std::forward(args)...)); 77 | } 78 | 79 | template 80 | explicit BoostAtomicSharedPtrAdaptor(Args&& ... args) 81 | { 82 | delegate.store(boost::make_shared(std::forward(args)...)); 83 | } 84 | 85 | template 86 | friend void swap(BoostAtomicSharedPtrAdaptor& a, BoostAtomicSharedPtrAdaptor& b) 87 | { 88 | for(;;) 89 | { 90 | auto tmp = a.delegate.load(bcon); 91 | if(a.delegate.compare_exchange_weak(tmp, b.delegate, barl)) 92 | { 93 | b.delegate = tmp; 94 | break; 95 | } 96 | } 97 | } 98 | 99 | template 100 | friend void swapProtected(BoostAtomicSharedPtrAdaptor& a, BoostAtomicSharedPtrAdaptor& b) 101 | { 102 | boost::shared_ptr tmp = a.delegate.load(); 103 | a.delegate.store(b.delegate.load()); 104 | b.delegate.store(tmp); 105 | } 106 | 107 | template 108 | void make(Args&& ... args) 109 | { 110 | makeType(std::forward(args)...); 111 | } 112 | 113 | template 114 | void makeType(Args&& ... args) 115 | { 116 | delegate.store(boost::make_shared(std::forward(args)...)); 117 | } 118 | 119 | void makeArray(sz length) 120 | { 121 | delegate.store(boost::make_shared < T[]>(length)); 122 | } 123 | 124 | public: 125 | 126 | ~BoostAtomicSharedPtrAdaptor() { } 127 | 128 | public: 129 | 130 | T& operator*() const 131 | { 132 | return *get(); 133 | } 134 | 135 | T* operator->() const 136 | { 137 | return get(); 138 | } 139 | 140 | T& operator[](sz index) const 141 | { 142 | assert(index < length()); 143 | return get()[index]; 144 | } 145 | 146 | T* get(std::memory_order mo = ocon) const 147 | { 148 | boost::memory_order bmo = bcon; 149 | switch(mo) 150 | { 151 | case orlx: 152 | bmo = brlx; 153 | break; 154 | case ocon: 155 | bmo = bcon; 156 | break; 157 | case oacq: 158 | bmo = bacq; 159 | break; 160 | case orls: 161 | bmo = brls; 162 | break; 163 | case oarl: 164 | bmo = barl; 165 | break; 166 | case oseq: 167 | bmo = bseq; 168 | break; 169 | } 170 | 171 | return delegate.load(bmo).get(); 172 | } 173 | 174 | sz length() const 175 | { 176 | return delegate->length(); 177 | } 178 | 179 | 180 | public: 181 | 182 | bool operator==(std::nullptr_t)const 183 | { 184 | return get() == nullptr; 185 | } 186 | 187 | template 188 | bool operator==(V* const that)const 189 | { 190 | return get() == that; 191 | } 192 | 193 | template 194 | bool operator==(BoostAtomicSharedPtrAdaptor const& that) const 195 | { 196 | return that.get() == get(); 197 | } 198 | 199 | template 200 | bool operator!=(V const& that) const noexcept 201 | { 202 | return !(*this == that); 203 | } 204 | 205 | public: 206 | 207 | BoostAtomicSharedPtrAdaptor& operator=(std::nullptr_t const& that) 208 | { 209 | delegate.store(boost::atomic_shared_ptr(that)); 210 | return *this; 211 | } 212 | 213 | template 214 | BoostAtomicSharedPtrAdaptor& operator=(BoostAtomicSharedPtrAdaptor& that) 215 | { 216 | boost::shared_ptr tmp = boost::static_pointer_cast(that.delegate.load()); 217 | delegate.store(tmp); 218 | return *this; 219 | } 220 | 221 | BoostAtomicSharedPtrAdaptor& setProtected(nullptr_t const that) 222 | { 223 | return *this = nullptr; 224 | } 225 | 226 | template 227 | BoostAtomicSharedPtrAdaptor& setProtected(BoostAtomicSharedPtrAdaptor& that) 228 | { 229 | return *this = that; 230 | } 231 | }; 232 | 233 | 234 | } /* namespace frc */ 235 | } /* namespace terrain */ 236 | 237 | 238 | namespace std 239 | { 240 | 241 | 242 | template 243 | struct hash> 244 | { 245 | 246 | std::size_t operator()(const terrain::frc::BoostAtomicSharedPtrAdaptor& k) const 247 | { 248 | return std::hash > (k.delegate)(); 249 | } 250 | }; 251 | } 252 | 253 | -------------------------------------------------------------------------------- /benchmark/BoostSharedPtrAdaptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: BoostSharedPtrAdaptor.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace terrain 25 | { 26 | namespace frc 27 | { 28 | // Aliases for boost memory orders 29 | const boost::memory_order brlx = boost::memory_order_relaxed; 30 | const boost::memory_order bcon = boost::memory_order_consume; 31 | const boost::memory_order bacq = boost::memory_order_acquire; 32 | const boost::memory_order brls = boost::memory_order_release; 33 | const boost::memory_order barl = boost::memory_order_acq_rel; 34 | const boost::memory_order bseq = boost::memory_order_seq_cst; 35 | 36 | /** 37 | * Adaptor class that delegates to a boost::atomic 38 | */ 39 | template 40 | class BoostSharedPtrAdaptor 41 | { 42 | private: 43 | boost::atomic> delegate; 44 | 45 | public: 46 | 47 | BoostSharedPtrAdaptor() 48 | { 49 | delegate.store(boost::shared_ptr(nullptr), brls); 50 | } 51 | 52 | BoostSharedPtrAdaptor(BoostSharedPtrAdaptor&& that) 53 | { 54 | delegate.store(that.delegate.load(bacq), brls); 55 | that.delegate.store(boost::shared_ptr(nullptr), brls); 56 | }; 57 | 58 | BoostSharedPtrAdaptor(BoostSharedPtrAdaptor const& that) 59 | { 60 | delegate.store(that.delegate.load(bacq), brls); 61 | } 62 | 63 | template 64 | BoostSharedPtrAdaptor(BoostSharedPtrAdaptor const& that) 65 | { 66 | delegate.store(that.delegate.load(bacq), brls); 67 | } 68 | 69 | template 70 | BoostSharedPtrAdaptor(BoostSharedPtrAdaptor& that) : 71 | BoostSharedPtrAdaptor((BoostSharedPtrAdaptor const&)that) 72 | { 73 | ; 74 | } 75 | 76 | template 77 | explicit BoostSharedPtrAdaptor(Args&& ... args) 78 | { 79 | delegate.store(boost::make_shared(boost::forward(args)...), brls); 80 | } 81 | 82 | template 83 | explicit BoostSharedPtrAdaptor(Args&& ... args) 84 | { 85 | delegate.store(boost::make_shared(boost::forward(args)...), brls); 86 | } 87 | 88 | friend void swap(BoostSharedPtrAdaptor& a, BoostSharedPtrAdaptor& b) 89 | { 90 | swap(a.delegate, b.delegate); 91 | } 92 | 93 | friend void swapProtected(BoostSharedPtrAdaptor& a, BoostSharedPtrAdaptor& b) 94 | { 95 | boost::shared_ptr tmp = a.delegate.load(bacq); 96 | a.delegate.store(b.delegate.load(bacq), brlx); 97 | b.delegate.store(tmp, brls); 98 | } 99 | 100 | template 101 | void make(Args&& ... args) 102 | { 103 | makeType(std::forward(args)...); 104 | } 105 | 106 | template 107 | void makeType(Args&& ... args) 108 | { 109 | delegate.store(boost::make_shared(boost::forward(args)...), brls); 110 | } 111 | 112 | void makeArray(sz length) 113 | { 114 | delegate.store(boost::make_shared < T[]>(length), brls); 115 | } 116 | 117 | public: 118 | 119 | ~BoostSharedPtrAdaptor() { } 120 | 121 | public: 122 | 123 | T& operator*() const 124 | { 125 | return *get(); 126 | } 127 | 128 | T* operator->() const 129 | { 130 | return get(); 131 | } 132 | 133 | T& operator[](sz index) const 134 | { 135 | assert(index < length()); 136 | return get()[index]; 137 | } 138 | 139 | T* get(std::memory_order mo = ocon) const 140 | { 141 | boost::memory_order bmo = bcon; 142 | switch(mo) 143 | { 144 | case orlx: 145 | bmo = brlx; 146 | break; 147 | case ocon: 148 | bmo = bcon; 149 | break; 150 | case oacq: 151 | bmo = bacq; 152 | break; 153 | case orls: 154 | bmo = brls; 155 | break; 156 | case oarl: 157 | bmo = barl; 158 | break; 159 | case oseq: 160 | bmo = bseq; 161 | break; 162 | } 163 | 164 | return delegate.load(bmo).get(); 165 | } 166 | 167 | sz length() const 168 | { 169 | return delegate.load(bacq)->length(); 170 | } 171 | 172 | public: 173 | 174 | bool operator==(std::nullptr_t)const 175 | { 176 | return get() == nullptr; 177 | } 178 | 179 | template 180 | bool operator==(V* const that)const 181 | { 182 | return get() == that; 183 | } 184 | 185 | template 186 | bool operator==(BoostSharedPtrAdaptor const& that) const 187 | { 188 | return that.get() == get(); 189 | } 190 | 191 | template 192 | bool operator!=(V const& that) const noexcept 193 | { 194 | return !(*this == that); 195 | } 196 | 197 | public: 198 | 199 | BoostSharedPtrAdaptor& operator=(std::nullptr_t const& that) 200 | { 201 | delegate.store(boost::shared_ptr(nullptr), brls); 202 | return *this; 203 | } 204 | 205 | template 206 | BoostSharedPtrAdaptor& operator=(BoostSharedPtrAdaptor& that) 207 | { 208 | delegate.store(that.delegate.load(bacq), brls); 209 | return *this; 210 | } 211 | 212 | BoostSharedPtrAdaptor& setProtected(nullptr_t const that) 213 | { 214 | delegate.store(boost::shared_ptr(nullptr), brlx); 215 | return *this; 216 | } 217 | 218 | template 219 | BoostSharedPtrAdaptor& setProtected(BoostSharedPtrAdaptor& that) 220 | { 221 | delegate.store(that.delegate.load(brlx), brls); 222 | return *this; 223 | } 224 | }; 225 | 226 | 227 | } /* namespace frc */ 228 | } /* namespace terrain */ 229 | 230 | 231 | namespace std 232 | { 233 | 234 | template 235 | struct hash> 236 | { 237 | 238 | std::size_t operator()(const terrain::frc::BoostSharedPtrAdaptor& k) const 239 | { 240 | return std::hash> (k.delegate)(); 241 | } 242 | }; 243 | } 244 | 245 | -------------------------------------------------------------------------------- /benchmark/Concurrent_Struct_Helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Concurrent_Struct_Helpers.h 3 | * Copyright 2017, 2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace terrain 20 | { 21 | namespace benchmarks 22 | { 23 | namespace cds 24 | { 25 | 26 | static std::random_device rd; 27 | static std::mt19937_64 rng(rd()); 28 | 29 | template 30 | inline void data_struct_insert(Key key, Value value) 31 | { 32 | return; 33 | }; 34 | 35 | template 36 | inline void data_struct_insert(Key key, Value value, DataStruct1 dataStruct1, 37 | DataStructs... dataStructs) 38 | { 39 | dataStruct1->insert(key, value); 40 | data_struct_insert(key, value, dataStructs...); 41 | }; 42 | 43 | template 44 | void shuffle_nodes(Iter const& begin, Iter const& end) 45 | { 46 | std::shuffle(begin, end, rng); 47 | }; 48 | 49 | template 50 | static void build_random_structs(lng numNodes, 51 | DataStructs... dataStructs) // TODO: allow for any data type here (not just long) 52 | { 53 | std::vector orderedNodes(numNodes); 54 | for(lng i = 0; i < numNodes; ++i) 55 | orderedNodes[i] = i; 56 | shuffle_nodes(orderedNodes.begin(), orderedNodes.end()); 57 | for(lng i = 0; i < numNodes; ++i) 58 | { 59 | data_struct_insert(orderedNodes[i], orderedNodes[i], dataStructs...); 60 | } 61 | orderedNodes.clear(); 62 | } 63 | 64 | } /* namespace cds */ 65 | } /* namespace benchmarks */ 66 | } /* namespace terrain */ 67 | -------------------------------------------------------------------------------- /benchmark/Concurrent_Struct_Insert_Tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Concurrent_Struct_Insert_Tests.h 3 | * Copyright 2017, 2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "Concurrent_Struct_Helpers.h" 18 | 19 | namespace terrain 20 | { 21 | namespace benchmarks 22 | { 23 | namespace cds 24 | { 25 | namespace insert_test 26 | { 27 | static constexpr lng maxThreads = 32; 28 | static constexpr lng incThreads = 1; 29 | static constexpr lng numTrials = 3; 30 | 31 | static constexpr lng maxInserts = 10000; 32 | static constexpr lng incInserts = 1000; 33 | 34 | template 35 | static void test(string struct_name, TestType testMode, bool useFRC = false, 36 | bool printSizes = false) 37 | { 38 | frc::FRCToken token; 39 | 40 | // Timing 41 | std::vector threads; 42 | std::vector threadTimes(maxThreads); 43 | std::vector sizes; 44 | std::vector times; 45 | 46 | lng incIters, maxIters; 47 | lng numThreads = 1, numInserts; 48 | switch(testMode) 49 | { 50 | default: // case TestType::workload 51 | { 52 | // Iterate over number of inserts 53 | incIters = incInserts; 54 | maxIters = maxInserts; 55 | numThreads = maxThreads; 56 | break; 57 | } 58 | case TestType::threads: 59 | { 60 | // Iterate over threads 61 | incIters = incThreads; 62 | maxIters = maxThreads; 63 | numInserts = maxInserts; 64 | break; 65 | } 66 | case TestType::singleWorkload: 67 | { 68 | // Single threaded, but iterate over workload size 69 | numThreads = 1; 70 | incIters = incInserts; 71 | maxIters = maxInserts; 72 | break; 73 | } 74 | case TestType::singleThreads: 75 | { 76 | // Single threaded, but iterate over numbers of threads 77 | numThreads = 1; 78 | numInserts = maxInserts; 79 | incIters = incThreads; 80 | maxIters = maxThreads; 81 | break; 82 | } 83 | } 84 | 85 | for(lng numIters = incIters; numIters <= maxIters; numIters += incIters) 86 | { 87 | sizes.push_back(numIters); 88 | switch(testMode) 89 | { 90 | default: // case TestType::workload 91 | { 92 | numInserts = numIters; 93 | break; 94 | } 95 | case TestType::threads: 96 | { 97 | numThreads = numIters; 98 | break; 99 | } 100 | case TestType::singleWorkload: 101 | { 102 | numInserts = maxThreads * numIters; 103 | break; 104 | } 105 | case TestType::singleThreads: 106 | { 107 | numInserts = numIters * maxInserts; 108 | break; 109 | } 110 | } 111 | 112 | boost::barrier threadBarrier(numThreads); 113 | 114 | std::cout << "numInserts = " << numInserts << "\tnumThreads = " << numThreads << std::endl; 115 | 116 | std::vector orderedNodes(numInserts * numThreads); 117 | for(lng i = 0; i < numInserts * numThreads; ++i) 118 | orderedNodes[i] = i; 119 | shuffle_nodes(orderedNodes.begin(), orderedNodes.end()); 120 | 121 | for(lng trial = 0; trial < numTrials; ++trial) 122 | { 123 | frc::detail::FRCManager::collect(); 124 | DataStruct dataStruct; 125 | threads.clear(); 126 | for(lng t = 0; t < numThreads; ++t) 127 | threads.emplace_back([&](lng t2) 128 | { 129 | bindToProcessor(t2); 130 | frc::FRCToken token; 131 | 132 | DataStruct* pDataStruct = &dataStruct; 133 | std::chrono::high_resolution_clock::time_point tic, toc; 134 | 135 | threadBarrier.wait(); // Get all threads ready to go 136 | 137 | tic = std::chrono::high_resolution_clock::now(); 138 | for(lng i = t2 * numInserts; i < (t2 + 1) * numInserts; ++i) 139 | { 140 | pDataStruct->insert(orderedNodes[i], orderedNodes[i]); 141 | } 142 | toc = std::chrono::high_resolution_clock::now(); 143 | threadTimes[t2] = std::chrono::duration_cast> 144 | (toc - tic).count(); 145 | threadBarrier.wait(); 146 | frc::detail::FRCManager::collect(); 147 | }, t); 148 | for(auto& t : threads) 149 | t.join(); 150 | if(trial == numTrials - 1) 151 | times.push_back(std::accumulate(threadTimes.begin(), threadTimes.end(), 152 | 0.) / (numInserts * numThreads)); 153 | } 154 | } 155 | 156 | std::ofstream ofile; 157 | string threadAppend = (testMode == TestType::workload 158 | || testMode == TestType::singleWorkload) ? "" : "_th"; 159 | if(printSizes) 160 | { 161 | ofile.open(struct_name + "_insert_test" + threadAppend + ".txt"); 162 | ofile << sizes[0]; 163 | for(ulng i = 1; i < sizes.size(); ++i) 164 | ofile << "," << sizes[i]; 165 | ofile << std::endl; 166 | } 167 | else 168 | ofile.open(struct_name + "_insert_test" + threadAppend + ".txt", std::ios::app); 169 | ofile << std::scientific << std::setprecision(10) << times[0]; 170 | for(ulng i = 1; i < sizes.size(); ++i) 171 | ofile << "," << times[i]; 172 | ofile << std::endl; 173 | } 174 | 175 | } /* namespace insert_test */ 176 | } /* namespace cds */ 177 | } /* namespace benchmarks */ 178 | } /* namespace terrain */ 179 | -------------------------------------------------------------------------------- /benchmark/Concurrent_Struct_Remove_Tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Concurrent_Struct_Remove_Tests.h 3 | * Copyright 2017, 2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "Concurrent_Struct_Helpers.h" 18 | 19 | namespace terrain 20 | { 21 | namespace benchmarks 22 | { 23 | namespace cds 24 | { 25 | namespace remove_test 26 | { 27 | static constexpr lng maxThreads = 32; 28 | static constexpr lng incThreads = 1; 29 | 30 | static constexpr lng numTrials = 3; 31 | 32 | static constexpr lng maxRemoves = 10000; 33 | static constexpr lng incRemoves = 1000; 34 | 35 | template 36 | static void test(string struct_name, TestType testMode, bool useFRC = false, 37 | bool printSizes = false) 38 | { 39 | std::cout.setf(std::ios::unitbuf); 40 | frc::FRCToken token; 41 | 42 | // Timing 43 | std::vector threads; 44 | std::vector threadTimes(maxThreads); 45 | std::vector sizes; 46 | std::vector times; 47 | 48 | lng incIters, maxIters; 49 | lng numThreads = 1, numRemoves; 50 | switch(testMode) 51 | { 52 | default: // case TestType::workload 53 | { 54 | // Iterate over number of removes 55 | incIters = incRemoves; 56 | maxIters = maxRemoves; 57 | numThreads = maxThreads; 58 | break; 59 | } 60 | case TestType::threads: 61 | { 62 | // Iterate over threads 63 | incIters = incThreads; 64 | maxIters = maxThreads; 65 | numRemoves = maxRemoves; 66 | break; 67 | } 68 | case TestType::singleWorkload: 69 | { 70 | // Single threaded, but iterate over workload size 71 | numThreads = 1; 72 | incIters = incRemoves; 73 | maxIters = maxRemoves; 74 | break; 75 | } 76 | case TestType::singleThreads: 77 | { 78 | // Single threaded, but iterate over numbers of threads 79 | numThreads = 1; 80 | numRemoves = maxRemoves; 81 | incIters = incThreads; 82 | maxIters = maxThreads; 83 | break; 84 | } 85 | } 86 | 87 | for(lng numIters = incIters; numIters <= maxIters; numIters += incIters) 88 | { 89 | sizes.push_back(numIters); 90 | switch(testMode) 91 | { 92 | default: // case TestType::workload 93 | { 94 | numRemoves = numIters; 95 | break; 96 | } 97 | case TestType::threads: 98 | { 99 | numThreads = numIters; 100 | break; 101 | } 102 | case TestType::singleWorkload: 103 | { 104 | numRemoves = maxThreads * numIters; 105 | break; 106 | } 107 | case TestType::singleThreads: 108 | { 109 | numRemoves = numIters * maxRemoves; 110 | break; 111 | } 112 | } 113 | 114 | boost::barrier threadBarrier(numThreads); 115 | 116 | std::cout << "numRemoves = " << numRemoves << "\tnumThreads = " << numThreads << std::endl; 117 | 118 | std::vector orderedNodes(numRemoves * numThreads); 119 | for(lng i = 0; i < numRemoves * numThreads; ++i) 120 | orderedNodes[i] = i; 121 | shuffle_nodes(orderedNodes.begin(), orderedNodes.end()); 122 | 123 | for(lng trial = 0; trial < numTrials; ++trial) 124 | { 125 | frc::detail::FRCManager::collect(); 126 | // Build the data struct 127 | std::unique_ptr dataStruct(new DataStruct()); 128 | build_random_structs(maxThreads * maxRemoves, dataStruct.get()); 129 | 130 | threads.clear(); 131 | for(lng t = 0; t < numThreads; ++t) 132 | threads.emplace_back([&](lng t2) 133 | { 134 | bindToProcessor(t2); 135 | frc::FRCToken token; 136 | 137 | DataStruct* pDataStruct = dataStruct.get(); 138 | std::chrono::high_resolution_clock::time_point tic, toc; 139 | 140 | threadBarrier.wait(); // Get all threads ready to go 141 | 142 | tic = std::chrono::high_resolution_clock::now(); 143 | for(lng i = t2 * numRemoves; i < (t2 + 1)*numRemoves; ++i) 144 | { 145 | pDataStruct->remove(orderedNodes[i]); 146 | } 147 | toc = std::chrono::high_resolution_clock::now(); 148 | threadTimes[t2] = std::chrono::duration_cast> 149 | (toc - tic).count(); 150 | 151 | threadBarrier.wait(); 152 | if(t == 0) 153 | dataStruct.reset(); 154 | threadBarrier.wait(); 155 | 156 | for(sz i = 0; i < 32; ++i) 157 | frc::detail::FRCManager::collect(); 158 | }, t); 159 | for(auto& t : threads) 160 | t.join(); 161 | if(trial == numTrials - 1) 162 | times.push_back(std::accumulate(threadTimes.begin(), threadTimes.end(), 163 | 0.) / (numRemoves * numThreads)); 164 | } 165 | frc::detail::FRCManager::collect(); 166 | } 167 | std::ofstream ofile; 168 | string threadAppend = (testMode == TestType::workload 169 | || testMode == TestType::singleWorkload) ? "" : "_th"; 170 | if(printSizes) 171 | { 172 | ofile.open(struct_name + "_remove_test" + threadAppend + ".txt"); 173 | ofile << sizes[0]; 174 | for(ulng i = 1; i < sizes.size(); ++i) 175 | ofile << "," << sizes[i]; 176 | ofile << std::endl; 177 | } 178 | else 179 | ofile.open(struct_name + "_remove_test" + threadAppend + ".txt", std::ios::app); 180 | ofile << std::scientific << std::setprecision(10) << times[0]; 181 | for(ulng i = 1; i < sizes.size(); ++i) 182 | ofile << "," << times[i]; 183 | ofile << std::endl; 184 | } 185 | 186 | } /* namespace remove_test */ 187 | } /* namespace cds */ 188 | } /* namespace benchmarks */ 189 | } /* namespace terrain */ 190 | -------------------------------------------------------------------------------- /benchmark/Datasets.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Datasets.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include "Datasets.h" 16 | 17 | namespace terrain 18 | { 19 | namespace benchmarks 20 | { 21 | namespace datasets 22 | { 23 | 24 | 25 | extern Dataset& get_distinct_1() 26 | { 27 | static auto ds = loadDataset("distinct_1.txt"); 28 | return ds; 29 | } 30 | 31 | extern Dataset& get_skew1_1() 32 | { 33 | static auto ds = loadDataset("skew1_1.txt"); 34 | return ds; 35 | } 36 | 37 | extern Dataset loadDataset(std::string name) 38 | { 39 | Dataset dataset; 40 | dataset.filename = std::string("./../../benchmark/data/") + name; 41 | 42 | std::cout << "Loading dataset " << name << "." << std::endl; 43 | 44 | std::ifstream iFile; 45 | iFile.open(dataset.filename); 46 | 47 | std::stringstream ss; 48 | ss << iFile.rdbuf(); 49 | dataset.raw = ss.str(); 50 | 51 | auto chars = dataset.raw.c_str(); 52 | auto len = dataset.raw.size(); 53 | 54 | sz begin = 0; 55 | for(sz i = 0; i < len; ++i) 56 | { 57 | if(chars[i] == '\n') 58 | { 59 | dataset.keys.emplace_back(chars + begin, i - begin); 60 | ++i; // skip newline 61 | begin = i; 62 | } 63 | } 64 | iFile.close(); 65 | 66 | std::cout << "Loaded " << dataset.keys.size() << " keys from dataset " << name << "." << 67 | std::endl; 68 | return dataset; 69 | } 70 | 71 | 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /benchmark/Datasets.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Datasets.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | //#include 20 | #include 21 | #include 22 | 23 | 24 | namespace terrain 25 | { 26 | namespace benchmarks 27 | { 28 | namespace datasets 29 | { 30 | 31 | struct Dataset 32 | { 33 | std::string filename; 34 | std::vector keys; 35 | std::string raw; 36 | }; 37 | 38 | extern Dataset& get_distinct_1(); 39 | extern Dataset& get_skew1_1(); 40 | extern Dataset loadDataset(std::string name); 41 | 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /benchmark/Dealloc_Time.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Dealloc_Time.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include "Basic_Tests.h" 17 | 18 | using namespace std; 19 | using namespace std::chrono; 20 | 21 | using namespace terrain; 22 | using namespace terrain::frc; 23 | using Type = terrain::benchmarks::basic::Type; 24 | 25 | namespace terrain 26 | { 27 | namespace benchmarks 28 | { 29 | namespace basic 30 | { 31 | namespace dealloc_time 32 | { 33 | 34 | static auto malloc_body = [&](lng numValues, double& time) 35 | { 36 | high_resolution_clock::time_point tic, toc; 37 | { 38 | // Allocate the ptrs 39 | std::unique_ptr < Type*[] > ptrs = std::make_unique < Type*[]>(numValues); 40 | for(lng i = 0; i < numValues; ++i) 41 | ptrs[i] = new Type(5); 42 | tic = high_resolution_clock::now(); 43 | for(lng i = 0; i < numValues; ++i) 44 | delete ptrs[i]; 45 | } 46 | toc = high_resolution_clock::now(); 47 | time = duration_cast> (toc - tic).count(); 48 | }; 49 | 50 | static auto std_body = [&](lng numValues, double& time) 51 | { 52 | high_resolution_clock::time_point tic, toc; 53 | { 54 | // Allocate the ptrs 55 | std::unique_ptr < std::shared_ptr[] > ptrs = std::make_unique < std::shared_ptr[]> 56 | (numValues); 57 | for(lng i = 0; i < numValues; ++i) 58 | ptrs[i] = std::make_shared(5); 59 | tic = high_resolution_clock::now(); 60 | } 61 | toc = high_resolution_clock::now(); 62 | time = duration_cast> (toc - tic).count(); 63 | }; 64 | 65 | static auto bsp_body = [&](lng numValues, double& time) 66 | { 67 | high_resolution_clock::time_point tic, toc; 68 | { 69 | // Allocate the ptrs 70 | std::unique_ptr < boost::shared_ptr[] > ptrs = std::make_unique 71 | < boost::shared_ptr[]> 72 | (numValues); 73 | for(lng i = 0; i < numValues; ++i) 74 | ptrs[i] = boost::make_shared(5); 75 | tic = high_resolution_clock::now(); 76 | } 77 | toc = high_resolution_clock::now(); 78 | time = duration_cast> (toc - tic).count(); 79 | }; 80 | 81 | static auto bas_body = [&](lng numValues, double& time) 82 | { 83 | high_resolution_clock::time_point tic, toc; 84 | { 85 | // Allocate the ptrs 86 | std::unique_ptr < boost::atomic_shared_ptr[] > ptrs = 87 | std::make_unique < boost::atomic_shared_ptr[]>(numValues); 88 | for(lng i = 0; i < numValues; ++i) 89 | ptrs[i] = boost::make_shared(5); 90 | tic = high_resolution_clock::now(); 91 | } 92 | toc = high_resolution_clock::now(); 93 | time = duration_cast> (toc - tic).count(); 94 | }; 95 | 96 | static auto frc_s_m_body = [&](lng numValues, double& time) 97 | { 98 | high_resolution_clock::time_point tic, toc; 99 | { 100 | // Allocate the ptrs 101 | unique_ptr < AtomicPointer[] > ptrs = make_unique < AtomicPointer[]>(numValues); 102 | for(lng i = 0; i < numValues; ++i) 103 | ptrs[i].make(5); 104 | tic = high_resolution_clock::now(); 105 | } 106 | toc = high_resolution_clock::now(); 107 | time = duration_cast> (toc - tic).count(); 108 | }; 109 | 110 | static auto frc_p_m_body = [&](lng numValues, double& time) 111 | { 112 | time = 0.; 113 | static constexpr lng pinSetSize = terrain::frc::detail::FRCConstants::pinSetSize; 114 | high_resolution_clock::time_point tic, toc; 115 | 116 | for(lng counter = pinSetSize; counter < numValues; counter += pinSetSize) 117 | { 118 | lng values = std::min(numValues - counter, pinSetSize); 119 | { 120 | // Allocate the ptrs 121 | std::unique_ptr < PrivatePointer[] > ptrs(new PrivatePointer[values]); 122 | for(lng i = 0; i < values; ++i) 123 | ptrs[i].make(5); 124 | tic = high_resolution_clock::now(); 125 | } 126 | toc = high_resolution_clock::now(); 127 | 128 | time += duration_cast> (toc - tic).count(); 129 | } 130 | }; 131 | 132 | TEST(FRC_Basic, dealloc_time_malloc) 133 | { 134 | test("dealloc_time", malloc_body, workload, false, false, true); 135 | } 136 | 137 | TEST(FRC_Basic, dealloc_time_std) 138 | { 139 | test("dealloc_time", std_body, workload, false, false, false); 140 | } 141 | 142 | TEST(FRC_Basic, dealloc_time_bsp) 143 | { 144 | test("dealloc_time", bsp_body, workload, false, false, false); 145 | } 146 | 147 | TEST(FRC_Basic, dealloc_time_bas) 148 | { 149 | test("dealloc_time", bas_body, workload, false, false, false); 150 | } 151 | 152 | TEST(FRC_Basic, dealloc_time_frc_s_m) 153 | { 154 | test("dealloc_time", frc_s_m_body, workload, true, true, false); 155 | } 156 | 157 | TEST(FRC_Basic, dealloc_time_frc_p_m) 158 | { 159 | test("dealloc_time", frc_p_m_body, workload, true, true, false); 160 | } 161 | 162 | TEST(FRC_Basic, dealloc_time_th_malloc) 163 | { 164 | test("dealloc_time_th", malloc_body, threads, false, false, true); 165 | } 166 | 167 | TEST(FRC_Basic, dealloc_time_th_std) 168 | { 169 | test("dealloc_time_th", std_body, threads, false, false, false); 170 | } 171 | 172 | TEST(FRC_Basic, dealloc_time_th_bsp) 173 | { 174 | test("dealloc_time_th", bsp_body, threads, false, false, false); 175 | } 176 | 177 | TEST(FRC_Basic, dealloc_time_th_bas) 178 | { 179 | test("dealloc_time_th", bas_body, threads, false, false, false); 180 | } 181 | 182 | TEST(FRC_Basic, dealloc_time_th_frc_s_m) 183 | { 184 | test("dealloc_time_th", frc_s_m_body, threads, true, true, false); 185 | } 186 | 187 | TEST(FRC_Basic, dealloc_time_th_frc_p_m) 188 | { 189 | test("dealloc_time_th", frc_p_m_body, threads, true, true, false); 190 | } 191 | 192 | } /* namespace dealloc_time */ 193 | } /* namespace basic */ 194 | } /* namespace benchmarks */ 195 | } /* namespace terrain */ 196 | -------------------------------------------------------------------------------- /benchmark/RawPtrAdaptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: RawPtrAdaptor.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace terrain 23 | { 24 | namespace frc 25 | { 26 | 27 | /** 28 | * Adaptor class that delegates to a counted raw pointer 29 | * \warning Not thread safe! Only for single threaded use 30 | */ 31 | template 32 | class RawPtrAdaptor 33 | { 34 | template 35 | friend class RawPtrAdaptor; 36 | 37 | private: 38 | 39 | T* delegate; 40 | 41 | public: 42 | 43 | RawPtrAdaptor() 44 | { 45 | delegate = nullptr; 46 | } 47 | 48 | ~RawPtrAdaptor() 49 | { 50 | decrementAndDestroyRelaxed(delegate); 51 | delegate = nullptr; 52 | } 53 | 54 | RawPtrAdaptor(RawPtrAdaptor&& that) 55 | { 56 | delegate = that.delegate; 57 | that.delegate = nullptr; 58 | }; 59 | 60 | RawPtrAdaptor(RawPtrAdaptor const& that) 61 | { 62 | delegate = that.delegate; 63 | incrementRelaxed(delegate); 64 | } 65 | 66 | template 67 | RawPtrAdaptor(RawPtrAdaptor const& that) 68 | { 69 | delegate = static_cast(that.delegate); 70 | incrementRelaxed(delegate); 71 | } 72 | 73 | template 74 | RawPtrAdaptor(RawPtrAdaptor& that) : 75 | RawPtrAdaptor((RawPtrAdaptor const&)that) 76 | { 77 | ; 78 | } 79 | 80 | template 81 | explicit RawPtrAdaptor(Args&& ... args) 82 | { 83 | delegate = detail::makeNewObject(1, std::forward(args)...); 84 | } 85 | 86 | template 87 | explicit RawPtrAdaptor(Args&& ... args) 88 | { 89 | delegate = static_cast(detail::makeNewObject(1, std::forward(args)...)); 90 | } 91 | 92 | template 93 | friend void swap(RawPtrAdaptor& a, RawPtrAdaptor& b) 94 | { 95 | T* tmp = a.delegate; 96 | a.delegate = b.delegate; 97 | b.delegate = tmp; 98 | } 99 | 100 | template 101 | friend void swapProtected(RawPtrAdaptor& a, RawPtrAdaptor& b) 102 | { 103 | T* tmp = a.delegate; 104 | a.delegate = b.delegate; 105 | b.delegate = tmp; 106 | } 107 | 108 | template 109 | void make(Args&& ... args) 110 | { 111 | makeType(std::forward(args)...); 112 | } 113 | 114 | template 115 | void makeType(Args&& ... args) 116 | { 117 | decrementAndDestroyRelaxed(delegate); 118 | delegate = static_cast(detail::makeNewObject(1, std::forward(args)...)); 119 | 120 | } 121 | 122 | void makeArray(sz length) 123 | { 124 | decrementAndDestroyRelaxed(delegate); 125 | delegate = detail::makeNewArray(1, length); 126 | } 127 | 128 | public: 129 | 130 | T& operator*() const 131 | { 132 | return *get(); 133 | } 134 | 135 | T* operator->() const 136 | { 137 | return get(); 138 | } 139 | 140 | T& operator[](sz index) const 141 | { 142 | assert(index < length()); 143 | return get()[index]; 144 | } 145 | 146 | T* get(std::memory_order mo = ocon) const 147 | { 148 | return delegate; 149 | } 150 | 151 | sz length() const 152 | { 153 | return detail::getObjectHeader(delegate)->length(); 154 | } 155 | 156 | 157 | public: 158 | 159 | bool operator==(std::nullptr_t)const 160 | { 161 | return get() == nullptr; 162 | } 163 | 164 | template 165 | bool operator==(V* const that)const 166 | { 167 | return get() == that; 168 | } 169 | 170 | template 171 | bool operator==(RawPtrAdaptor const& that) const 172 | { 173 | return that.get() == get(); 174 | } 175 | 176 | template 177 | bool operator!=(V const& that) const noexcept 178 | { 179 | return !(*this == that); 180 | } 181 | 182 | public: 183 | 184 | RawPtrAdaptor& operator=(std::nullptr_t const& that) 185 | { 186 | decrementAndDestroyRelaxed(delegate); 187 | delegate = nullptr; 188 | return *this; 189 | } 190 | 191 | template 192 | RawPtrAdaptor& operator=(RawPtrAdaptor& that) 193 | { 194 | T* old = delegate; 195 | delegate = static_cast(that.delegate); 196 | incrementRelaxed(delegate); 197 | decrementAndDestroyRelaxed(old); 198 | return *this; 199 | } 200 | 201 | RawPtrAdaptor& setProtected(nullptr_t const that) 202 | { 203 | return *this = nullptr; 204 | } 205 | 206 | template 207 | RawPtrAdaptor& setProtected(RawPtrAdaptor& that) 208 | { 209 | return *this = that; 210 | } 211 | 212 | private: 213 | 214 | static void incrementRelaxed(T* ptr) 215 | { 216 | if(!ptr) 217 | return; 218 | auto header = detail::getObjectHeader(ptr); 219 | auto c = header->count.load(orlx) + 1; 220 | header->count.store(c, orlx); 221 | } 222 | 223 | static uint decrementAndDestroyRelaxed(T* ptr) 224 | { 225 | if(!ptr) 226 | return 0; 227 | 228 | auto header = detail::getObjectHeader(ptr); 229 | auto c = header->count.load(orlx) - 1; 230 | if(c == 0) 231 | header->destroy(); 232 | else 233 | header->count.store(c, orlx); 234 | return c; 235 | } 236 | }; 237 | 238 | 239 | } /* namespace frc */ 240 | } /* namespace terrain */ 241 | 242 | 243 | namespace std 244 | { 245 | 246 | /** 247 | * std lib specialization of std::hash for RawPtrAdaptor's 248 | */ 249 | template 250 | struct hash> 251 | { 252 | 253 | std::size_t operator()(const terrain::frc::RawPtrAdaptor& k) const 254 | { 255 | return std::hash(k.delegate)(); 256 | } 257 | }; 258 | } 259 | 260 | -------------------------------------------------------------------------------- /benchmark/STDSharedPtrAdaptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: STDSharedPtrAdaptor.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | 20 | namespace terrain 21 | { 22 | namespace frc 23 | { 24 | 25 | /** 26 | * Adaptor class that delegates to a std::shared_ptr 27 | */ 28 | template 29 | class STDSharedPtrAdaptor 30 | { 31 | template 32 | friend class STDSharedPtrAdaptor; 33 | 34 | 35 | private: 36 | std::shared_ptr delegate; 37 | 38 | public: 39 | 40 | STDSharedPtrAdaptor() 41 | { 42 | ; 43 | } 44 | 45 | STDSharedPtrAdaptor(STDSharedPtrAdaptor&& that) 46 | { 47 | std::atomic_store_explicit( 48 | &delegate, 49 | std::atomic_load_explicit(&that.delegate, orlx), 50 | orls); 51 | }; 52 | 53 | STDSharedPtrAdaptor(STDSharedPtrAdaptor const& that) 54 | { 55 | std::atomic_store_explicit( 56 | &delegate, 57 | std::atomic_load_explicit(&that.delegate, oacq), 58 | orls); 59 | } 60 | 61 | template 62 | STDSharedPtrAdaptor(STDSharedPtrAdaptor const& that) 63 | { 64 | std::atomic_store_explicit( 65 | &delegate, 66 | std::static_pointer_cast(std::atomic_load_explicit(&that.delegate, oacq)), 67 | orls); 68 | } 69 | 70 | template 71 | STDSharedPtrAdaptor(STDSharedPtrAdaptor& that) : 72 | STDSharedPtrAdaptor((STDSharedPtrAdaptor const&)that) 73 | { 74 | ; 75 | } 76 | 77 | template 78 | explicit STDSharedPtrAdaptor(Args&& ... args) 79 | { 80 | make(std::forward(args)...); 81 | } 82 | 83 | template 84 | explicit STDSharedPtrAdaptor(Args&& ... args) 85 | { 86 | makeType(std::forward(args)...); 87 | } 88 | 89 | template 90 | friend void swap(STDSharedPtrAdaptor& a, STDSharedPtrAdaptor& b) 91 | { 92 | auto tmp = std::atomic_load_explicit(&a.delegate, orlx); 93 | std::atomic_store_explicit(&a.delegate, b.delegate, orls); 94 | std::atomic_store_explicit(&b.delegate, tmp, orls); 95 | // std::swap(a.delegate, b.delegate); 96 | } 97 | 98 | template 99 | friend void swapProtected(STDSharedPtrAdaptor& a, STDSharedPtrAdaptor& b) 100 | { 101 | auto tmp = std::atomic_load_explicit(&a.delegate, orlx); 102 | std::atomic_store_explicit(&a.delegate, b.delegate, orls); 103 | std::atomic_store_explicit(&b.delegate, tmp, orls); 104 | // b.delegate = std::atomic_exchange_explicit(&a.delegate, b.delegate, oarl); 105 | } 106 | 107 | template 108 | void make(Args&& ... args) 109 | { 110 | makeType(std::forward(args)...); 111 | } 112 | 113 | template 114 | void makeType(Args&& ... args) 115 | { 116 | std::shared_ptr temp = std::make_shared(std::forward(args)...); 117 | std::atomic_store_explicit(&delegate, temp, orls); 118 | } 119 | 120 | void makeArray(sz length) 121 | { 122 | std::atomic_store_explicit(&delegate, std::make_shared < T[]>(length), orls); 123 | } 124 | 125 | public: 126 | 127 | ~STDSharedPtrAdaptor() { } 128 | 129 | public: 130 | 131 | T& operator*() const 132 | { 133 | return *get(); 134 | } 135 | 136 | T* operator->() const 137 | { 138 | return get(); 139 | } 140 | 141 | T& operator[](sz index) const 142 | { 143 | assert(index < length()); 144 | return get()[index]; 145 | } 146 | 147 | T* get(std::memory_order mo = ocon) const 148 | { 149 | return std::atomic_load_explicit(&delegate, mo).get(); 150 | } 151 | 152 | sz length() const 153 | { 154 | return delegate->length(); 155 | } 156 | 157 | 158 | public: 159 | 160 | bool operator==(std::nullptr_t)const 161 | { 162 | return get() == nullptr; 163 | } 164 | 165 | template 166 | bool operator==(V* const that)const 167 | { 168 | return get() == that; 169 | } 170 | 171 | template 172 | bool operator==(STDSharedPtrAdaptor const& that) const 173 | { 174 | return that.get() == get(); 175 | } 176 | 177 | template 178 | bool operator!=(V const& that) const noexcept 179 | { 180 | return !(*this == that); 181 | } 182 | 183 | public: 184 | 185 | STDSharedPtrAdaptor& operator=(std::nullptr_t const& that) 186 | { 187 | std::atomic_store_explicit(&delegate, std::shared_ptr(that), orls); 188 | return *this; 189 | } 190 | 191 | template 192 | STDSharedPtrAdaptor& operator=(STDSharedPtrAdaptor& that) 193 | { 194 | std::atomic_store_explicit( 195 | &delegate, 196 | std::static_pointer_cast(std::atomic_load_explicit(&that.delegate, oacq)), 197 | orls); 198 | return *this; 199 | } 200 | 201 | STDSharedPtrAdaptor& setProtected(nullptr_t const that) 202 | { 203 | return *this = nullptr; 204 | } 205 | 206 | template 207 | STDSharedPtrAdaptor& setProtected(STDSharedPtrAdaptor& that) 208 | { 209 | return *this = that; 210 | } 211 | }; 212 | 213 | 214 | } /* namespace frc */ 215 | } /* namespace terrain */ 216 | 217 | 218 | namespace std 219 | { 220 | 221 | template 222 | struct hash> 223 | { 224 | 225 | std::size_t operator()(const terrain::frc::STDSharedPtrAdaptor& k) const 226 | { 227 | return std::hash > (k.delegate)(); 228 | } 229 | }; 230 | } 231 | 232 | -------------------------------------------------------------------------------- /benchmark/Slop_Size.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Slop_Size.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include "Concurrent_Struct_Helpers.h" 19 | #include "./cds/BST.h" 20 | 21 | using namespace terrain; 22 | using namespace terrain::frc; 23 | 24 | namespace terrain 25 | { 26 | namespace benchmarks 27 | { 28 | namespace slop_size 29 | { 30 | static constexpr lng numIters = 512 * 1024; 31 | static constexpr lng numThreads = 32; 32 | using Type = lng; 33 | 34 | // For loop test 35 | void test_1() 36 | { 37 | FRCToken tkn; 38 | // Initialize the threads 39 | std::vector threads; 40 | threads.clear(); 41 | boost::barrier threadBarrier(numThreads); 42 | 43 | // Run the test 44 | for(lng t = 0; t < numThreads; ++t) 45 | { 46 | threads.emplace_back([&](lng t2) 47 | { 48 | if(numThreads <= hardwareConcurrency()) 49 | bindToProcessor(t2); 50 | FRCToken tkn; 51 | 52 | threadBarrier.wait(); // Get all threads ready to go 53 | for(lng i = 0; i < numIters; ++i) 54 | AtomicPointer(12); 55 | }, t); 56 | } 57 | for(auto& t : threads) 58 | t.join(); 59 | threads.clear(); 60 | } 61 | 62 | // Recreates BST remove test to only do a single run 63 | using FRC_BST = terrain::cds::BST; 64 | static constexpr lng maxRemoves = 10000; 65 | static constexpr lng numRemoves = 1000; 66 | 67 | void test_2() 68 | { 69 | frc::FRCToken token; 70 | 71 | // Ready the threads 72 | std::vector threads; 73 | boost::barrier threadBarrier(numThreads); 74 | 75 | // Pre-build the tree 76 | FRC_BST dataStruct; 77 | terrain::benchmarks::cds::build_random_structs(maxRemoves * numThreads, &dataStruct); 78 | 79 | // Ready the remove sequence 80 | std::vector orderedNodes(numThreads * numRemoves); 81 | for(lng i = 0; i < numRemoves * numThreads; ++i) 82 | orderedNodes[i] = i; 83 | terrain::benchmarks::cds::shuffle_nodes(orderedNodes.begin(), orderedNodes.end()); 84 | 85 | for(lng t = 0; t < numThreads; ++t) 86 | { 87 | threads.emplace_back([&](lng t2) 88 | { 89 | bindToProcessor(t2); 90 | frc::FRCToken token; 91 | 92 | FRC_BST* pDataStruct = &dataStruct; 93 | 94 | threadBarrier.wait(); // Get all threads ready to go 95 | for(lng i = t2 * numRemoves; i < (t2 + 1)*numRemoves; ++i) 96 | pDataStruct->remove(orderedNodes[i]); 97 | }, t); 98 | } 99 | for(auto& t : threads) 100 | t.join(); 101 | } 102 | 103 | } /* namespace slop_size */ 104 | } /* namespace benchmarks */ 105 | } /* namespace terrain */ 106 | 107 | TEST(FRC_Slop, slop_size_1) 108 | { 109 | terrain::benchmarks::slop_size::test_1(); 110 | } 111 | 112 | TEST(FRC_Slop, slop_size_2) 113 | { 114 | terrain::benchmarks::slop_size::test_2(); 115 | } 116 | -------------------------------------------------------------------------------- /benchmark/Static_Tree_Router_Test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Static_Tree_Router_Test.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | namespace terrain 19 | { 20 | namespace test 21 | { 22 | namespace static_tree_router 23 | { 24 | 25 | static constexpr lng numThreads = 32; 26 | static constexpr lng numIters = 1e6; 27 | 28 | // Proxy for the FRCManager 29 | struct MockManager 30 | { 31 | StaticTreeRouter barrier; 32 | StaticTreeRouter router0; 33 | StaticTreeRouter router1; 34 | StaticTreeRouter* routers; 35 | atm currentEpoch; 36 | 37 | MockManager(): barrier(numThreads), router0(numThreads), router1(numThreads), 38 | routers(&router0), currentEpoch(0) 39 | { 40 | sz epoch = getCurrentEpoch(); 41 | auto& router = getRouter(epoch); 42 | for(lng t = 0; t < numThreads; ++t) 43 | router.acquire(t); 44 | } 45 | 46 | sz getCurrentEpoch() 47 | { 48 | return currentEpoch.load(oacq); 49 | } 50 | 51 | StaticTreeRouter& getRouter(sz epoch) 52 | { 53 | return routers[epoch & 1]; 54 | } 55 | 56 | bool help() 57 | { 58 | for(sz i = 0; i < 8; ++i) 59 | { 60 | sz epoch = getCurrentEpoch(); 61 | auto& router = getRouter(epoch); 62 | 63 | sz groupIndex = router.findAcquired(); 64 | if(groupIndex == StaticTreeRouter::notFound) 65 | { 66 | continue; 67 | } 68 | 69 | if(!router.release(groupIndex)) 70 | { 71 | continue; 72 | } 73 | 74 | sz success = 0; 75 | if(getCurrentEpoch() == epoch) 76 | { 77 | success = FastRNG::next() & 127; // 1 in 256 chance of failure 78 | } 79 | 80 | if(!success) 81 | { 82 | router.acquire(groupIndex); 83 | continue; 84 | } 85 | 86 | ++epoch; 87 | getRouter(epoch).acquire(groupIndex); 88 | 89 | if(!barrier.cyclicRelease(groupIndex)) 90 | { 91 | return true; 92 | } 93 | std::cout << "End of epoch " << epoch - 1 << std::endl; 94 | currentEpoch.store(epoch, orls); 95 | return true; 96 | } 97 | return false; 98 | } 99 | }; 100 | 101 | void test() 102 | { 103 | // Make the MockManager; 104 | MockManager Manager; 105 | 106 | // Initialize threads 107 | std::vector threads; 108 | 109 | for(lng t = 0; t < numThreads; ++t) 110 | { 111 | threads.emplace_back([&](sz t2) 112 | { 113 | bindToProcessor(t2); 114 | for(lng i = 0; i < numIters; ++i) 115 | Manager.help(); 116 | }, t); 117 | } 118 | for(auto& t : threads) 119 | t.join(); 120 | } 121 | 122 | } /* namespace static_tree_router */ 123 | } /* namespace test */ 124 | } /* namespace terrain */ 125 | 126 | 127 | 128 | TEST(FRC_Test, static_tree_router) 129 | { 130 | terrain::test::static_tree_router::test(); 131 | } 132 | -------------------------------------------------------------------------------- /benchmark/Timing_Test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Timing_Test.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include "cds/BST.h" 18 | 19 | // #define TIME_FRC 20 | 21 | namespace terrain 22 | { 23 | namespace benchmarks 24 | { 25 | namespace timing_test 26 | { 27 | 28 | using FRC_BST = terrain::cds::BST; 29 | using DataStruct = FRC_BST; 30 | 31 | static constexpr lng numThreads = 32; 32 | 33 | static void test() 34 | { 35 | frc::FRCToken token; 36 | 37 | // Ready threads 38 | std::vector threads; 39 | 40 | // Load the data into vectors 41 | std::vector keys; 42 | std::vector queries; 43 | std::ifstream iFile; 44 | iFile.open("./../../benchmark/data/distinct_1.txt"); 45 | std::copy(std::istream_iterator(iFile), std::istream_iterator(), 46 | std::back_inserter(keys)); 47 | iFile.close(); 48 | std::cout << "Loaded " << keys.size() << " keys into memory" << std::endl; 49 | iFile.open("./../../benchmark/data/skew1_1.txt"); 50 | std::copy(std::istream_iterator(iFile), std::istream_iterator(), 51 | std::back_inserter(queries)); 52 | iFile.close(); 53 | std::cout << "Loaded " << queries.size() << " queries into memory" << std::endl; 54 | lng numKeys = keys.size(); 55 | lng numThreadKeys = (numKeys + numThreads) / numThreads; 56 | lng numQueries = queries.size(); 57 | lng numThreadQueries = (numQueries + numThreads) / numThreads; 58 | 59 | // Ready the data structure 60 | DataStruct dataStruct; 61 | DataStruct* pDataStruct = &dataStruct; 62 | 63 | // Perform insertion 64 | threads.clear(); 65 | for(lng t = 0; t < numThreads; ++t) 66 | { 67 | threads.emplace_back([&](lng t2) 68 | { 69 | bindToProcessor(t2); 70 | frc::FRCToken token; 71 | 72 | lng insertBegin = t2 * numThreadKeys; 73 | lng insertEnd = std::min((t2 + 1) * numThreadKeys, numKeys); 74 | 75 | for(lng i = insertBegin; i < insertEnd; ++i) 76 | pDataStruct->insert(keys[i], keys[i]); 77 | }, t); 78 | } 79 | for(auto& t : threads) 80 | t.join(); 81 | 82 | std::cout << "Finished inserting keys." << std::endl; 83 | 84 | // Read 85 | threads.clear(); 86 | for(lng t = 0; t < numThreads; ++t) 87 | { 88 | threads.emplace_back([&](lng t2) 89 | { 90 | bindToProcessor(t2); 91 | frc::FRCToken token; 92 | 93 | lng readBegin = t2 * numThreadQueries; 94 | lng readEnd = std::min((t2 + 1) * numThreadQueries, numQueries); 95 | 96 | for(lng i = readBegin; i < readEnd; ++i) 97 | { 98 | string v; 99 | pDataStruct->find(queries[i], v); 100 | } 101 | }, t); 102 | } 103 | for(auto& t : threads) 104 | t.join(); 105 | 106 | std::cout << "Finished reading queries" << std::endl; 107 | 108 | threads.clear(); 109 | for(lng t = 0; t < numThreads; ++t) 110 | { 111 | threads.emplace_back([&](lng t2) 112 | { 113 | bindToProcessor(t2); 114 | frc::FRCToken token; 115 | 116 | lng removeBegin = t2 * numThreadKeys; 117 | lng removeEnd = std::min((t2 + 1) * numThreadKeys, numKeys); 118 | 119 | for(lng i = removeBegin; i < removeEnd; ++i) 120 | pDataStruct->remove(keys[i]); 121 | }, t); 122 | } 123 | for(auto& t : threads) 124 | t.join(); 125 | 126 | std::cout << "Finished removing keys" << std::endl; 127 | } 128 | 129 | } /* namespace timing_test */ 130 | } /* namespace benchmarks */ 131 | } /* namespace terrain */ 132 | 133 | TEST(FRC_Timing, timing_test) 134 | { 135 | terrain::benchmarks::timing_test::test(); 136 | } 137 | -------------------------------------------------------------------------------- /benchmark/cds/Comparators.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Comparators.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #ifndef CTOOLS_ctools_COMPARATORS_H_ 16 | #define CTOOLS_ctools_COMPARATORS_H_ 17 | 18 | #include "IComparable.h" 19 | 20 | #include 21 | #include 22 | 23 | 24 | namespace terrain 25 | { 26 | 27 | template 28 | using ComparatorFunction = nm(*)(T const& a, T const& b); 29 | 30 | template 31 | struct DefaultComparator 32 | { 33 | inline bool operator()(T const& a, T const& b) 34 | { 35 | return std::less()(a, b); 36 | } 37 | }; 38 | 39 | template 40 | struct DefaultComparator < T, 41 | typename boost::enable_if, T>>::type > 42 | { 43 | inline bool operator()(T const& a, T const& b) 44 | { 45 | return ((T*)(&a))->compareTo(*((T*)(&b))); 46 | } 47 | }; 48 | 49 | template 50 | class DefaultComparator < T*, 51 | typename boost::enable_if, T>>::type > 52 | { 53 | public: 54 | inline bool operator()(T* const& a, T* const& b) 55 | { 56 | return a->compareTo(b); 57 | } 58 | }; 59 | 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /benchmark/cds/HashFunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: HashFunctions.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "IHashable.h" 18 | 19 | #include 20 | #include 21 | 22 | #include "hashFunctions.h" 23 | 24 | 25 | namespace terrain 26 | { 27 | 28 | template 29 | using HashFunction = sz(*)(T const& a); 30 | 31 | template 32 | struct DefaultHasher 33 | { 34 | inline sz operator()(T const& a) 35 | { 36 | return std::hash()(a); 37 | } 38 | }; 39 | 40 | template 41 | struct DefaultHasher 42 | { 43 | inline sz operator()(T const* const a) 44 | { 45 | return fastPtrHashFast(a); 46 | } 47 | }; 48 | 49 | template 50 | struct DefaultHasher < T, 51 | typename boost::enable_if, T>>::type > 52 | { 53 | inline sz operator()(T const& a) 54 | { 55 | return ((T*) &a)->getHashCode(); 56 | } 57 | }; 58 | 59 | template 60 | struct DefaultHasher < T*, 61 | typename boost::enable_if, T>>::type > 62 | { 63 | inline sz operator()(T const* const a) 64 | { 65 | return ((T*) a)->getHashCode(); 66 | } 67 | }; 68 | 69 | #define CTOOLS_DEFAULT_HASH(type, function) \ 70 | template<> \ 71 | struct DefaultHasher \ 72 | { \ 73 | inline sz operator()(type a) \ 74 | { \ 75 | return function((sz)a); \ 76 | }\ 77 | }; 78 | 79 | 80 | template 81 | inline T passthroughFunction(T key) 82 | { 83 | return key; 84 | } 85 | 86 | 87 | CTOOLS_DEFAULT_HASH(lng, twHash64); 88 | 89 | CTOOLS_DEFAULT_HASH(ulng, twHash64); 90 | 91 | CTOOLS_DEFAULT_HASH(intt, twHash32); 92 | 93 | CTOOLS_DEFAULT_HASH(uint, twHash32); 94 | 95 | CTOOLS_DEFAULT_HASH(sht, twHash16); 96 | 97 | CTOOLS_DEFAULT_HASH(usht, twHash16); 98 | 99 | CTOOLS_DEFAULT_HASH(sbyte, passthroughFunction); 100 | 101 | CTOOLS_DEFAULT_HASH(byte, passthroughFunction); 102 | 103 | #undef CTOOLS_DEFAULT_HASH 104 | 105 | template 106 | struct HashFuncWrapper 107 | { 108 | inline sz operator()(T k) 109 | { 110 | return hashFunction(k); 111 | } 112 | }; 113 | 114 | struct FastPtrHasher 115 | { 116 | inline sz operator()(void const* const k) 117 | { 118 | return fastPtrHashFast(k); 119 | } 120 | }; 121 | 122 | template 123 | struct PassthroughHashFunction 124 | { 125 | inline sz operator()(T k) 126 | { 127 | return (sz) k; 128 | } 129 | }; 130 | 131 | 132 | template 133 | inline sz defaultHashOf(T e) 134 | { 135 | DefaultHasher h; 136 | return h(e); 137 | } 138 | 139 | } /* namespace terrain */ 140 | -------------------------------------------------------------------------------- /benchmark/cds/IComparable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: IComparable.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace terrain 20 | { 21 | 22 | /** 23 | * Utility interface class for implementing comparable objects 24 | */ 25 | template 26 | class IComparable 27 | { 28 | private: 29 | 30 | static inline IComparable* deconst(IComparable const* const instance) 31 | { 32 | return ((IComparable*) instance); 33 | } 34 | 35 | public: 36 | 37 | virtual nm compareTo(T& that) = 0; 38 | 39 | nm compareTo(T const& that) const 40 | { 41 | return ((IComparable*) this)->compareTo(*(T*) &that); 42 | } 43 | 44 | virtual ~IComparable() 45 | { 46 | } 47 | 48 | virtual bool operator>(T const& that) const 49 | { 50 | return compareTo(that) > 0; 51 | } 52 | 53 | virtual bool operator>=(T const& that) const 54 | { 55 | return compareTo(that) >= 0; 56 | } 57 | 58 | virtual bool operator<(T const& that) const 59 | { 60 | return compareTo(that) < 0; 61 | } 62 | 63 | virtual bool operator<=(T const& that) const 64 | { 65 | return compareTo(that) <= 0; 66 | } 67 | 68 | virtual bool operator==(T const& that) const 69 | { 70 | return compareTo(that) == 0; 71 | } 72 | }; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /benchmark/cds/IHashable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: IHashtable.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace terrain 20 | { 21 | /** 22 | * Utility interface class for implementing 23 | * Objects with a getHashCode() method. 24 | * 25 | * Compatible with IHashMap's. 26 | */ 27 | template 28 | class IHashable 29 | { 30 | public: 31 | 32 | virtual sz getHashCode() = 0; 33 | 34 | virtual ~IHashable() 35 | { 36 | } 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /benchmark/cds/binarySearch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: binarySearch.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "Comparators.h" 20 | 21 | 22 | namespace terrain 23 | { 24 | 25 | namespace binarySearch_ 26 | { 27 | 28 | /** 29 | * A fast binary search algorithm. 30 | * http://eigenjoy.com/2011/01/21/worlds-fastest-binary-search/ 31 | * http://eigenjoy.com/2011/09/09/binary-search-revisited/ 32 | * 33 | * Assumes numElements > 0. 34 | * Returns the greatest index of an element less than or equal to key. 35 | * If no such index exists, 36 | */ 37 | template> 38 | static sz binarySearchCommon(RandomAccessIterator elements, 39 | sz const numElements, 40 | Key const& searchKey) 41 | { 42 | sz i = 0; 43 | sz b = (numElements <= 1) ? 0 : roundDownToPowerOfTwo(numElements); 44 | for(; b != 0; b /= 2) 45 | { 46 | sz j = i + b; 47 | if(numElements <= j) 48 | continue; 49 | 50 | if(Compare()(searchKey, elements[j])) //searchKey < elements[j] 51 | { 52 | //probe power of 2 sized region 53 | b /= 2; 54 | for(; b != 0; b /= 2) 55 | { 56 | //usually reduces to a CMOV instruction 57 | if(!Compare()(searchKey, elements[i + b])) //searchKey >= elements[i + b] 58 | i += b; 59 | } 60 | break; 61 | } 62 | else 63 | i = j; 64 | } 65 | return i; 66 | } 67 | } /* namespace binarySearch_ */ 68 | 69 | /** 70 | * Return the greatest unsigned i where elements[i] <= searchKey. 71 | * If i does not exist (elements is empty, or key < elements[0]) 72 | * then return -1. 73 | */ 74 | template> 75 | static nm binarySearch(RandomAccessIterator elements, nm const numElements, 76 | Key const& searchKey) 77 | { 78 | if(numElements == 0) 79 | return -1; 80 | auto i = binarySearch_::binarySearchCommon(elements, numElements, searchKey); 81 | if(i == 0 && Compare()(searchKey, *elements)) 82 | return -1; 83 | return (nm) i; 84 | } 85 | 86 | /** 87 | * Return the greatest unsigned i where elements[i] <= searchKey. 88 | * If i does not exist (elements is empty, or key < elements[0]) 89 | * then return -1. 90 | */ 91 | template> 92 | static nm binarySearch(RandomAccessIterator from, RandomAccessIterator to, 93 | Key const& searchKey) 94 | { 95 | return binarySearch(from, (nm)(to - from), searchKey); 96 | } 97 | 98 | /** 99 | * Return the greatest unsigned i where elements[i] <= searchKey. 100 | * If i does not exist (elements is empty, or key < elements[0]) 101 | * then returns 0. 102 | */ 103 | template> 104 | static sz binarySearchUncorrected(RandomAccessIterator elements, 105 | sz const numElements, 106 | Key const& searchKey) 107 | { 108 | if(numElements == 0) 109 | return 0; 110 | return binarySearch_::binarySearchCommon(elements, numElements, searchKey); 111 | } 112 | 113 | /** 114 | * Return the greatest unsigned i where elements[i] <= searchKey. 115 | * If i does not exist (elements is empty, or key < elements[0]) 116 | * then returns 0. 117 | */ 118 | template> 119 | static sz binarySearchUncorrected(RandomAccessIterator from, 120 | RandomAccessIterator to, 121 | Key const& searchKey) 122 | { 123 | return binarySearchUncorrected(from, to - from, searchKey); 124 | } 125 | 126 | } /* namespace terrain */ 127 | -------------------------------------------------------------------------------- /benchmark/cds/hashFunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: hashFunctions.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | /* BASED ON WORK BY THOMAS WANG. */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | /** 22 | * A collection of simple fast integer and pointer hash functions. 23 | */ 24 | 25 | namespace terrain 26 | { 27 | /** 28 | * AKA Thomas Wang's integer hash function 29 | */ 30 | template 31 | inline static T twHash32_2(T Ptr) 32 | { 33 | T a = (sz) Ptr; 34 | a = ~a + (a << 15); 35 | a = a ^ (a >> 12); 36 | a = a + (a << 2); 37 | a = a ^ (a >> 4); 38 | a = a * 2057; 39 | a = a ^ (a >> 16); 40 | a = a ^ ((sz) Ptr >> 32); //added this for 64-bit pointers... 41 | return a; 42 | } 43 | 44 | /** 45 | * AKA Thomas Wang's integer hash function 46 | * Rumored to work poorly on multiples of 34 47 | * 48 | * >> We added an xor with the original value to reduce clustering on sequential inputs. 49 | */ 50 | template 51 | inline static T twHash32_3(T x) 52 | { 53 | T a = x; 54 | a = (a ^ 61) ^ (a >> 16); 55 | a = a + (a << 3); 56 | a = a ^ (a >> 4); 57 | a = a * 0x27d4eb2d; 58 | a = a ^ (a >> 15); 59 | return a ^ x; 60 | } 61 | 62 | 63 | inline static sz twHash32_3_ptr(sz a) 64 | { 65 | a = ((a >> 3) ^ 61) ^ (a >> 19); 66 | a = a + (a << 3); 67 | a = a ^ (a >> 4); 68 | a = a * 0x27d4eb2d; 69 | a = a ^ (a >> 15); 70 | return a; 71 | } 72 | 73 | 74 | inline static sz fastPtrHashFast(void const* const k) 75 | { 76 | return ((sz) k >> 3ULL) * 6364136223846793005ULL; 77 | } 78 | 79 | 80 | template 81 | inline static T twHash16(T key) 82 | { 83 | key ^= (key >> 10); 84 | key += (key << 3); 85 | key ^= (key >> 6); 86 | key += ~(key << 11); 87 | return key; 88 | } 89 | 90 | 91 | /** 92 | * Thomas Wang has a function that does it in 6 shifts (provided you use the low bits, hash & (SIZE-1), rather than the high bits if you can't use the whole value): 93 | */ 94 | template 95 | inline static T twHash32(T key) 96 | { 97 | key += ~(key << 15); 98 | key ^= (key >> 10); 99 | key += (key << 3); 100 | key ^= (key >> 6); 101 | key += ~(key << 11); 102 | key ^= (key >> 16); 103 | return key; 104 | } 105 | 106 | 107 | /** 108 | * Modified fast TW hash for 64-bit pointers. 109 | * Good as long as the low bits are used. 110 | */ 111 | inline static sz twHashPtrLow(sz key) 112 | { 113 | key = key >> 3; 114 | key += ~(key << 15); 115 | key ^= (key >> 10); 116 | key += (key << 3); 117 | key ^= (key >> 6); 118 | key += ~(key << 11); 119 | key ^= (key >> 16); 120 | return key; 121 | } 122 | 123 | 124 | /** 125 | * Thomas Wang's 64 bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm 126 | * 127 | * >> We added an xor with the original value to reduce clustering on sequential inputs. 128 | */ 129 | inline static ulng twHash64(ulng x) 130 | { 131 | ulng key = x; 132 | key += ~(key << 32); 133 | key ^= (key >> 22); 134 | key += ~(key << 13); 135 | key ^= (key >> 8); 136 | key += (key << 3); 137 | key ^= (key >> 15); 138 | key += ~(key << 27); 139 | key ^= (key >> 31); 140 | return key ^ x; 141 | } 142 | 143 | 144 | 145 | inline static ulng avHash64(ulng a) 146 | { 147 | a ^= a >> 23; 148 | a *= 0x2127599bf4325c37ULL; 149 | a ^= a >> 47; 150 | return a; 151 | } 152 | 153 | 154 | inline static uint avHash32(uint a) 155 | { 156 | a -= (a << 6); 157 | a ^= (a >> 17); 158 | a -= (a << 9); 159 | a ^= (a << 4); 160 | a -= (a << 3); 161 | a ^= (a << 10); 162 | a ^= (a >> 15); 163 | return a; 164 | } 165 | 166 | inline static ulng avHash32(ulng a) 167 | { 168 | a -= (a << 6); 169 | a ^= (a >> 17); 170 | a -= (a << 9); 171 | a ^= (a << 4); 172 | a -= (a << 3); 173 | a ^= (a << 10); 174 | a ^= (a >> 15); 175 | return a; 176 | } 177 | 178 | } /* namespace terrain */ 179 | -------------------------------------------------------------------------------- /benchmark/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: common.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #if __cplusplus < 201103L 18 | #define __cplusplus 201103L 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #include 40 | #include 41 | 42 | using auto_cpu_timer = boost::timer::auto_cpu_timer; 43 | 44 | namespace terrain 45 | { 46 | namespace benchmarks 47 | { 48 | 49 | inline void dprintt(char const* message, ...) 50 | { 51 | sz const bufferLength = 1024; 52 | sz const maxLength = bufferLength - sizeof(char); 53 | char buffer[bufferLength]; 54 | 55 | va_list argptr; 56 | va_start(argptr, message); 57 | vsnprintf(buffer, maxLength, message, argptr); 58 | va_end(argptr); 59 | 60 | std::cout << buffer; 61 | } 62 | 63 | static uint64_t __inline__ rdtsc(void) 64 | { 65 | unsigned int tick1, tickh; 66 | __asm__ __volatile__("rdtscp" : "=a"(tick1), "=d"(tickh)::"%ecx"); 67 | return ((uint64_t)tickh << 32) | tick1; 68 | } 69 | 70 | template 71 | std::unique_ptr make_unique_array_uninitialized(const std::size_t size) 72 | { 73 | return std::unique_ptr(new typename std::remove_extent::type[size]); 74 | } 75 | 76 | // Switches for whether to test over workload or test over number of threads or if we are testing a single threaded application 77 | 78 | enum TestType 79 | { 80 | workload, threads, singleWorkload, singleThreads 81 | }; 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | lib 2 | -------------------------------------------------------------------------------- /build/benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | cmake_minimum_required(VERSION 3.2) 6 | 7 | project(run_benchmarks) 8 | 9 | #------------------------------------------------------------- 10 | # PRELIMINARY DEFINITIONS 11 | #------------------------------------------------------------- 12 | 13 | # Set the root directory relative to this directory 14 | set(FRC_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) 15 | 16 | #------------------------------------------------------------- 17 | # INCLUDES 18 | #------------------------------------------------------------- 19 | 20 | include("${FRC_ROOT_DIR}/cmake/EL.cmake") 21 | include("${FRC_ROOT_DIR}/cmake/CompilerOptions.cmake") 22 | include("${FRC_ROOT_DIR}/cmake/GetFileHelpers.cmake") 23 | include("${FRC_ROOT_DIR}/cmake/OnlyFindStaticLibraries.cmake") 24 | 25 | # Include other necessary libraries 26 | include("${FRC_ROOT_DIR}/lib/BoostInstall.cmake") 27 | include("${FRC_ROOT_DIR}/lib/GoogleTestInstall.cmake") 28 | #include("${FRC_ROOT_DIR}/lib/BDWGCInstall.cmake") 29 | 30 | #------------------------------------------------------------- 31 | # CMAKE CONFIG 32 | #------------------------------------------------------------- 33 | 34 | # Override CMake variables for this project 35 | set(GLOBAL_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) 36 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH}) 37 | 38 | #------------------------------------------------------------- 39 | # DEPENDENCIES 40 | #------------------------------------------------------------- 41 | 42 | # Define the dependent sources and include directories for this project 43 | set(benchmark_source_dependencies ".") # relative to ${FRC_ROOT_DIR}/benchmark/ 44 | set(benchmark_include_dependencies ".") # relative to ${FRC_ROOT_DIR}/benchmark/ 45 | 46 | # Populates all_source_files, all_include_files, all_include_directories based on above dependencies 47 | include("${FRC_ROOT_DIR}/cmake/ProcessDependencies.cmake") 48 | 49 | #------------------------------------------------------------- 50 | # MANUAL FILE/DEPENDENCY MODIFICATIONS 51 | #------------------------------------------------------------ 52 | 53 | 54 | 55 | #------------------------------------------------------------- 56 | # TARGET DEFINITIONS 57 | #------------------------------------------------------------- 58 | 59 | # Add include directions for all targets 60 | include_directories( 61 | "${FRC_ROOT_DIR}/src" 62 | "${FRC_ROOT_DIR}/benchmarks" 63 | ${all_include_directories} 64 | ) 65 | 66 | # Define the main target for this project 67 | add_executable(${PROJECT_NAME} 68 | ${all_source_files} 69 | ) 70 | 71 | # Enforce that ExternalLibraries is up-to-date for this target 72 | add_dependencies(${PROJECT_NAME} boost) 73 | add_dependencies(${PROJECT_NAME} googletest) 74 | 75 | # Link libfrc 76 | include("${FRC_ROOT_DIR}/cmake/FRCLink.cmake") 77 | target_link_libraries(${PROJECT_NAME} pthread) 78 | 79 | # Link necessary external libraries 80 | include("${FRC_ROOT_DIR}/lib/BoostLink.cmake") 81 | include("${FRC_ROOT_DIR}/lib/GoogleTestLink.cmake") 82 | 83 | # Link other libraries as needed (note, might be a mix of dynamic/static linkage) 84 | 85 | target_link_libraries(${PROJECT_NAME} LINK_PUBLIC) 86 | target_link_libraries(${PROJECT_NAME} dl) 87 | 88 | target_link_libraries(${PROJECT_NAME} stdc++fs) 89 | 90 | #-------------------------------------------------------------- 91 | # EXTRA TARGETS AND COMMANDS 92 | #-------------------------------------------------------------- 93 | if(NOT DEFINED ROOT_PROJECT) 94 | add_custom_target(nuke COMMAND ${CMAKE_COMMAND} -P ${FRC_ROOT_DIR}/cmake/Nuke.cmake) 95 | endif() 96 | -------------------------------------------------------------------------------- /build/frc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | cmake_minimum_required(VERSION 3.2) 6 | 7 | project(frc) 8 | 9 | #------------------------------------------------------------- 10 | # PRELIMINARY DEFINITIONS 11 | #------------------------------------------------------------- 12 | 13 | # Set the root directory relative to this directory 14 | set(FRC_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) 15 | 16 | #------------------------------------------------------------- 17 | # INCLUDES 18 | #------------------------------------------------------------- 19 | 20 | include("${FRC_ROOT_DIR}/cmake/EL.cmake") 21 | include("${FRC_ROOT_DIR}/cmake/CompilerOptions.cmake") 22 | include("${FRC_ROOT_DIR}/cmake/GetFileHelpers.cmake") 23 | include("${FRC_ROOT_DIR}/cmake/OnlyFindStaticLibraries.cmake") 24 | 25 | # Include install of Booost 26 | include("${FRC_ROOT_DIR}/lib/BoostInstall.cmake") 27 | 28 | #------------------------------------------------------------- 29 | # CMAKE CONFIG 30 | #------------------------------------------------------------- 31 | 32 | # Override CMake variables for this project 33 | set(GLOBAL_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) 34 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH}) 35 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) 36 | 37 | #------------------------------------------------------------- 38 | # DEPENDENCIES 39 | #------------------------------------------------------------- 40 | 41 | # Define the dependent sources and include directories for this project 42 | set(src_source_dependencies ".") # relative to ${FRC_ROOT_DIR}/src 43 | 44 | # Populates all_source_files, all_include_files, all_include_directories based on above dependencies 45 | include("${FRC_ROOT_DIR}/cmake/ProcessDependencies.cmake") 46 | 47 | #------------------------------------------------------------- 48 | # MANUAL FILE/DEPENDENCY MODIFICATIONS 49 | #------------------------------------------------------------ 50 | 51 | 52 | 53 | #------------------------------------------------------------- 54 | # TARGET DEFINITIONS 55 | #------------------------------------------------------------- 56 | 57 | include_directories( 58 | "${FRC_ROOT_DIR}/src" 59 | ${all_include_directories} 60 | ) 61 | 62 | # Define the main target for this project 63 | add_library(${PROJECT_NAME} STATIC 64 | ${all_source_files} 65 | ) 66 | 67 | # Enforce that ExternalLibraries is up-to-date for this target 68 | add_dependencies(${PROJECT_NAME} boost) 69 | 70 | # Link necessary external libraries 71 | include("${FRC_ROOT_DIR}/lib/BoostLink.cmake") 72 | 73 | # Link other libraries as needed (note, might be a mix of dynamic/static linkage) 74 | target_link_libraries(${PROJECT_NAME} LINK_PUBLIC) 75 | 76 | #-------------------------------------------------------------- 77 | # EXTRA TARGETS AND COMMANDS 78 | #-------------------------------------------------------------- 79 | 80 | if(NOT DEFINED ROOT_PROJECT) 81 | add_custom_target(nuke COMMAND ${CMAKE_COMMAND} -P ${FRC_ROOT_DIR}/cmake/Nuke.cmake) 82 | endif() 83 | -------------------------------------------------------------------------------- /build/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | cmake_minimum_required(VERSION 3.2) 6 | 7 | project(unit_test) 8 | 9 | #------------------------------------------------------------- 10 | # PRELIMINARY DEFINITIONS 11 | #------------------------------------------------------------- 12 | 13 | # Set the root directory relative to this directory 14 | set(FRC_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) 15 | 16 | #------------------------------------------------------------- 17 | # INCLUDES 18 | #------------------------------------------------------------- 19 | 20 | include("${FRC_ROOT_DIR}/cmake/EL.cmake") 21 | include("${FRC_ROOT_DIR}/cmake/CompilerOptions.cmake") 22 | include("${FRC_ROOT_DIR}/cmake/GetFileHelpers.cmake") 23 | include("${FRC_ROOT_DIR}/cmake/OnlyFindStaticLibraries.cmake") 24 | 25 | # Include other necessary libraries 26 | include("${FRC_ROOT_DIR}/lib/BoostInstall.cmake") 27 | include("${FRC_ROOT_DIR}/lib/GoogleTestInstall.cmake") 28 | 29 | #------------------------------------------------------------- 30 | # CMAKE CONFIG 31 | #------------------------------------------------------------- 32 | 33 | # Override CMake variables for this project 34 | set(GLOBAL_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) 35 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GLOBAL_OUTPUT_PATH}) 36 | 37 | #------------------------------------------------------------- 38 | # DEPENDENCIES 39 | #------------------------------------------------------------- 40 | 41 | # Define the dependent sources and include directories for this project 42 | set(test_source_dependencies ".") # relative to ${FRC_ROOT_DIR}/test/ 43 | set(test_include_dependencies ".") # relative to ${FRC_ROOT_DIR}/test/ 44 | 45 | # Populates all_source_files, all_include_files, all_include_directories based on above dependencies 46 | include("${FRC_ROOT_DIR}/cmake/ProcessDependencies.cmake") 47 | 48 | #------------------------------------------------------------- 49 | # MANUAL FILE/DEPENDENCY MODIFICATIONS 50 | #------------------------------------------------------------ 51 | 52 | 53 | 54 | #------------------------------------------------------------- 55 | # TARGET DEFINITIONS 56 | #------------------------------------------------------------- 57 | 58 | # Add include directions for all targets 59 | include_directories( 60 | "${FRC_ROOT_DIR}/src" 61 | "${FRC_ROOT_DIR}/test" 62 | ${all_include_directories} 63 | ) 64 | 65 | # Define the main target for this project 66 | add_executable(${PROJECT_NAME} 67 | ${all_source_files} 68 | ) 69 | 70 | # Enforce that ExternalLibraries is up-to-date for this target 71 | add_dependencies(${PROJECT_NAME} boost) 72 | add_dependencies(${PROJECT_NAME} googletest) 73 | 74 | # Link libfrc 75 | include("${FRC_ROOT_DIR}/cmake/FRCLink.cmake") 76 | target_link_libraries(${PROJECT_NAME} pthread) 77 | 78 | # Link necessary external libraries 79 | include("${FRC_ROOT_DIR}/lib/BoostLink.cmake") 80 | include("${FRC_ROOT_DIR}/lib/GoogleTestLink.cmake") 81 | 82 | # Link other libraries as needed (note, might be a mix of dynamic/static linkage) 83 | 84 | target_link_libraries(${PROJECT_NAME} LINK_PUBLIC) 85 | target_link_libraries(${PROJECT_NAME} dl) 86 | 87 | target_link_libraries(${PROJECT_NAME} stdc++fs) 88 | 89 | #-------------------------------------------------------------- 90 | # EXTRA TARGETS AND COMMANDS 91 | #-------------------------------------------------------------- 92 | if(NOT DEFINED ROOT_PROJECT) 93 | add_custom_target(nuke COMMAND ${CMAKE_COMMAND} -P ${FRC_ROOT_DIR}/cmake/Nuke.cmake) 94 | endif() 95 | -------------------------------------------------------------------------------- /cmake/CompilerOptions.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 14) 2 | 3 | #-Wfatal-errors 4 | set(commonCompilerFlags "-ggdb -Wall -march=sandybridge -MMD -MP")# -Wl,--no-as-needed") 5 | 6 | if(DEFINED ENV{DISABLE_ASAN}) 7 | message("DISABLE_ASAN detected for this environment... disabling ASAN") 8 | set(commonDebugFlags "-O0 -DDEBUG") 9 | else() 10 | message("Using ASAN for this environment") 11 | set(commonDebugFlags "-O0 -DDEBUG -fno-omit-frame-pointer -fsanitize=address -fsanitize=leak -fsanitize=undefined") 12 | endif() 13 | set(commonReleaseFlags "-O3 -mtune=sandybridge -msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -DNDEBUG") 14 | set(cppFlags "-std=c++14") 15 | set(cFlags "-std=c11") 16 | 17 | set(commonLinkerFlags "-Wl,-rpath -Wl,$ENV{LD_LIBRARY_PATH}") 18 | 19 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 20 | # set Clang-specific flags here 21 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 22 | set(commonCompilerFlags "${commonCompilerFlags} -mtls-dialect=gnu2 -fuse-ld=gold") 23 | set(commonReleaseFlags "${commonReleaseFlags} -funsafe-loop-optimizations") 24 | set(cppFlags "${cppFlags} -fno-extern-tls-init") 25 | set(linkerReleaseFlags "-Wl,-gc-sections -Wl,--icf=all -Wl,--icf-iterations=4 -Wl,--relax") 26 | endif() 27 | 28 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${cppFlags} ${commonDebugFlags} ${commonCompilerFlags}") 29 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${cFlags} ${commonDebugFlags} ${commonCompilerFlags}") 30 | 31 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${cppFlags} ${commonReleaseFlags} ${commonCompilerFlags}") 32 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${cFlags} ${commonReleaseFlags} ${commonCompilerFlags}") 33 | 34 | set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS} ${commonLinkerFlags}") 35 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS} ${commonLinkerFlags} ${linkerReleaseFlags}") 36 | -------------------------------------------------------------------------------- /cmake/EL.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2016 Terrain Data, Inc. 3 | # 4 | 5 | if(NOT DEFINED EXTERNAL_LIBRARIES_PATH) 6 | 7 | if(NOT CMAKE_BUILD_TYPE) 8 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING 9 | "Choose the type of build. Options are: Debug, Release." 10 | FORCE) 11 | endif(NOT CMAKE_BUILD_TYPE) 12 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 13 | 14 | set(EXTERNAL_LIBRARIES_PATH ${FRC_ROOT_DIR}/lib) 15 | 16 | endif() 17 | 18 | include(ExternalProject) 19 | -------------------------------------------------------------------------------- /cmake/FRCLink.cmake: -------------------------------------------------------------------------------- 1 | if(NOT DEFINED ROOT_PROJECT) 2 | add_custom_target(frc_target 3 | WORKING_DIRECTORY ${FRC_ROOT_DIR}/build/frc 4 | COMMAND ${CMAKE_COMMAND} . 5 | COMMAND make -j32 6 | ) 7 | 8 | add_dependencies(${PROJECT_NAME} frc_target) 9 | 10 | add_library(frc STATIC IMPORTED) 11 | 12 | set_property(TARGET frc PROPERTY IMPORTED_LOCATION "${FRC_ROOT_DIR}/build/frc/lib/libfrc.a") 13 | endif() 14 | 15 | target_link_libraries(${PROJECT_NAME} frc) 16 | -------------------------------------------------------------------------------- /cmake/GetFileHelpers.cmake: -------------------------------------------------------------------------------- 1 | function(getSourceFiles source_name dir) 2 | FILE (GLOB_RECURSE files_c ${dir}/*.c) 3 | FILE (GLOB_RECURSE files_cpp ${dir}/*.cpp) 4 | SET(${source_name} ${files_c} ${files_cpp} PARENT_SCOPE) 5 | endfunction(getSourceFiles) 6 | 7 | function(getHeaderFiles source_name dir) 8 | FILE (GLOB_RECURSE files_h ${dir}/*.h) 9 | FILE (GLOB_RECURSE files_hpp ${dir}/*.hpp) 10 | SET(${source_name} ${files_h} ${files_hpp} PARENT_SCOPE) 11 | endfunction(getHeaderFiles) 12 | -------------------------------------------------------------------------------- /cmake/Nuke.cmake: -------------------------------------------------------------------------------- 1 | if(NOT DEFINED NUKE_CMAKE) 2 | set(NUKE_CMAKE "defined") 3 | 4 | set(DEL 5 | "CMakeFiles" 6 | "CMakeCache.txt" 7 | "cmake_install.cmake" 8 | "Makefile" 9 | "bin" 10 | "CPackConfig.cmake" 11 | "CPackSourceConfig.cmake" 12 | "tql3_grammar.cpp" 13 | "tql3_grammar.hpp" 14 | "tql3_grammar.out" 15 | "tql3_grammar.output" 16 | "lib" 17 | ) 18 | 19 | foreach(D ${DEL}) 20 | if(EXISTS ${D}) 21 | file(REMOVE_RECURSE ${D}) 22 | endif() 23 | endforeach() 24 | 25 | endif() 26 | -------------------------------------------------------------------------------- /cmake/OnlyFindStaticLibraries.cmake: -------------------------------------------------------------------------------- 1 | if (WIN32 OR MSVC) 2 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib") 3 | elseif (UNIX) 4 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") 5 | endif() 6 | -------------------------------------------------------------------------------- /cmake/ProcessDependencies.cmake: -------------------------------------------------------------------------------- 1 | set(all_source_files ) 2 | set(all_include_files ) 3 | set(all_include_directories ) 4 | 5 | foreach(dependency ${src_source_dependencies}) 6 | getSourceFiles(dep_files "${FRC_ROOT_DIR}/src/${dependency}") 7 | list(APPEND all_source_files ${dep_files}) 8 | endforeach(dependency) 9 | 10 | foreach(dependency ${test_source_dependencies}) 11 | getSourceFiles(dep_files "${FRC_ROOT_DIR}/test/${dependency}") 12 | list(APPEND all_source_files ${dep_files}) 13 | endforeach(dependency) 14 | 15 | foreach(dependency ${test_include_dependencies}) 16 | getHeaderFiles(dep_files "${FRC_ROOT_DIR}/test/${dependency}") 17 | list(APPEND all_include_files ${dep_files}) 18 | list(APPEND all_include_directories "${FRC_ROOT_DIR}/test/${dependency}") 19 | endforeach(dependency) 20 | 21 | foreach(dependency ${benchmark_source_dependencies}) 22 | getSourceFiles(dep_files "${FRC_ROOT_DIR}/benchmark/${dependency}") 23 | list(APPEND all_source_files ${dep_files}) 24 | endforeach(dependency) 25 | 26 | foreach(dependency ${benchmark_include_dependencies}) 27 | getHeaderFiles(dep_files "${FRC_ROOT_DIR}/benchmark/${dependency}") 28 | list(APPEND all_include_files ${dep_files}) 29 | list(APPEND all_include_directories "${FRC_ROOT_DIR}/benchmark/${dependency}") 30 | endforeach(dependency) 31 | 32 | -------------------------------------------------------------------------------- /lib/BoostInstall.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | add_definitions( 6 | -DBOOST_THREAD_USE_LIB 7 | ) 8 | 9 | set(Boost_NO_BOOST_CMAKE TRUE) 10 | set(BoostVersion 1.65.0) 11 | # Create build folder name derived from version 12 | string(REGEX REPLACE "beta\\.([0-9])$" "beta\\1" BoostFolderName ${BoostVersion}) 13 | string(REPLACE "." "_" BoostFolderName ${BoostFolderName}) 14 | set(BoostFolderName boost_${BoostFolderName}) 15 | set(Boost_Bootstrap_Command) 16 | if(UNIX) 17 | set(Boost_Bootstrap_Command ./bootstrap.sh) 18 | set(Boost_b2_Command ./b2) 19 | else() 20 | if(WIN32) 21 | set(Boost_Bootstrap_Command bootstrap.bat) 22 | set(Boost_b2_Command b2.exe) 23 | endif() 24 | endif() 25 | 26 | string(TOLOWER ${CMAKE_BUILD_TYPE} Boost_b2_variant) 27 | 28 | set(Boost_Download_Url "https://dl.bintray.com/boostorg/beta/1.65.0.beta.1/source/boost_1_65_0_beta1.tar.bz2") 29 | 30 | message("Downloading boost from: ${Boost_Download_Url}") 31 | 32 | include(ProcessorCount) 33 | ProcessorCount(NUM_PROCS) 34 | if(NUM_PROCS EQUAL 0) 35 | set(NUM_PROCS 1) 36 | endif() 37 | 38 | ExternalProject_Add(boost 39 | URL "${Boost_Download_Url}" 40 | URL_MD5 eefeba2b404a5918f8ed736a9c365dbb 41 | PREFIX "${EXTERNAL_LIBRARIES_PATH}" 42 | INSTALL_DIR "${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost" 43 | BUILD_IN_SOURCE 1 44 | UPDATE_COMMAND "" 45 | PATCH_COMMAND "" 46 | CONFIGURE_COMMAND ${Boost_Bootstrap_Command} 47 | BUILD_COMMAND ${Boost_b2_Command} install 48 | --without-python 49 | --without-mpi 50 | --disable-icu 51 | --prefix=${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost 52 | --threading=single,multi 53 | --link=static 54 | --variant=${Boost_b2_variant} 55 | -j${NUM_PROCS} 56 | --cxxflags="${CMAKE_CXX_FLAGS_CURRENT_CONFIGURATION}" 57 | --cflags="${CMAKE_C_FLAGS_CURRENT_CONFIGURATION}" 58 | --linkflags=${CMAKE_EXE_LINKER_FLAGS_CURRENT_CONFIGURATION} 59 | INSTALL_COMMAND true 60 | STEP_TARGETS build 61 | ) 62 | -------------------------------------------------------------------------------- /lib/BoostLink.cmake: -------------------------------------------------------------------------------- 1 | 2 | add_definitions( 3 | -DBOOST_THREAD_USE_LIB 4 | ) 5 | 6 | if(NOT WIN32) 7 | set(Boost_LIBRARY_DIR ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost/lib/) 8 | set(Boost_INCLUDE_DIR ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost/include/) 9 | else() 10 | set(Boost_LIBRARY_DIR ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost/lib/) 11 | set(Boost_INCLUDE_DIR ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/boost/include/${BoostFolderName}/) 12 | endif() 13 | 14 | include_directories(${Boost_INCLUDE_DIR}) 15 | set(CMAKE_INCLUDE_PATH "${Boost_INCLUDE_DIR}:${CMAKE_INCLUDE_PATH}") 16 | 17 | set(BOOST_DIR ${Boost_LIBRARY_DIR}) 18 | #link boost libraries in a working order (dependant lib before it's dependency) 19 | add_library(boost_log STATIC IMPORTED) 20 | set_property(TARGET boost_log PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_log.a) 21 | target_link_libraries(${PROJECT_NAME} boost_log) 22 | 23 | add_library(boost_log_setup STATIC IMPORTED) 24 | set_property(TARGET boost_log_setup PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_log_setup.a) 25 | target_link_libraries(${PROJECT_NAME} boost_log_setup) 26 | 27 | add_library(boost_random STATIC IMPORTED) 28 | set_property(TARGET boost_random PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_random.a) 29 | target_link_libraries(${PROJECT_NAME} boost_random) 30 | 31 | add_library(boost_program_options STATIC IMPORTED) 32 | set_property(TARGET boost_program_options PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_program_options.a) 33 | target_link_libraries(${PROJECT_NAME} boost_program_options) 34 | 35 | add_library(boost_filesystem STATIC IMPORTED) 36 | set_property(TARGET boost_filesystem PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_filesystem.a) 37 | target_link_libraries(${PROJECT_NAME} boost_filesystem) 38 | 39 | add_library(boost_timer STATIC IMPORTED) 40 | set_property(TARGET boost_timer PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_timer.a) 41 | target_link_libraries(${PROJECT_NAME} boost_timer) 42 | 43 | add_library(boost_chrono STATIC IMPORTED) 44 | set_property(TARGET boost_chrono PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_chrono.a) 45 | target_link_libraries(${PROJECT_NAME} boost_chrono) 46 | 47 | add_library(boost_system STATIC IMPORTED) 48 | set_property(TARGET boost_system PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_system.a) 49 | target_link_libraries(${PROJECT_NAME} boost_system) 50 | 51 | add_library(boost_thread STATIC IMPORTED) 52 | set_property(TARGET boost_thread PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_thread.a) 53 | 54 | target_link_libraries(${PROJECT_NAME} boost_thread) 55 | 56 | add_library(boost_date_time STATIC IMPORTED) 57 | set_property(TARGET boost_date_time PROPERTY IMPORTED_LOCATION ${BOOST_DIR}libboost_date_time.a) 58 | 59 | target_link_libraries(${PROJECT_NAME} boost_date_time) 60 | -------------------------------------------------------------------------------- /lib/GoogleTestInstall.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | # Google Test 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY "https://github.com/google/googletest.git" 8 | GIT_TAG master 9 | PREFIX "${EXTERNAL_LIBRARIES_PATH}" 10 | CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS_CURRENT_CONFIGURATION}" 11 | STEP_TARGETS build 12 | ) 13 | -------------------------------------------------------------------------------- /lib/GoogleTestLink.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # (C) 2017 Terrain Data, Inc. 3 | # 4 | 5 | #find_library(gtest NAMES gtest PATHS ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest/lib) 6 | add_library(gtest STATIC IMPORTED) 7 | set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest/lib/libgtest.a) 8 | target_link_libraries(${PROJECT_NAME} gtest) 9 | 10 | 11 | #find_library(gtest_main NAMES gtest_main PATHS ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest/lib) 12 | add_library(gtest_main STATIC IMPORTED) 13 | set_property(TARGET gtest_main PROPERTY IMPORTED_LOCATION ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest/lib/libgtest_main.a) 14 | target_link_libraries(${PROJECT_NAME} gtest_main) 15 | 16 | set(GTest_INCLUDE_DIR ${EXTERNAL_LIBRARIES_PATH}/${CMAKE_BUILD_TYPE}/googletest/include) 17 | include_directories(${GTest_INCLUDE_DIR}) 18 | set(CMAKE_INCLUDE_PATH "${GTest_INCLUDE_DIR}:${CMAKE_INCLUDE_PATH}") 19 | -------------------------------------------------------------------------------- /src/frc/detail/ArrayHeader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ArrayHeader.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "ObjectHeader.h" 18 | 19 | namespace terrain 20 | { 21 | namespace frc 22 | { 23 | namespace detail 24 | { 25 | 26 | class ArrayHeader 27 | { 28 | public: 29 | 30 | explicit ArrayHeader(intt count, uint typeCode, sz length_) noexcept : 31 | length_(length_), 32 | objectHeader(count, typeCode) 33 | { 34 | ; 35 | } 36 | 37 | ArrayHeader(ArrayHeader&& source) = delete; 38 | ArrayHeader(ArrayHeader const& source) = delete; 39 | ArrayHeader& operator=(ArrayHeader&& source) = delete; 40 | ArrayHeader& operator=(ArrayHeader const& source) = delete; 41 | 42 | void* getArray() const noexcept 43 | { 44 | return objectHeader.getObject(); 45 | } 46 | 47 | sz length() const noexcept 48 | { 49 | return length_; 50 | } 51 | 52 | private: 53 | sz length_; 54 | ObjectHeader objectHeader; 55 | }; 56 | 57 | 58 | } /* namespace detail */ 59 | } /* namespace frc */ 60 | } /* namespace terrain */ 61 | -------------------------------------------------------------------------------- /src/frc/detail/DestructorMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DestructorMap.h 3 | * Copyright 2014, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace terrain 25 | { 26 | namespace frc 27 | { 28 | namespace detail 29 | { 30 | 31 | class DestructorMap; 32 | class ObjectHeader; 33 | 34 | template 35 | static void destroyObject(ObjectHeader* header); 36 | 37 | template 38 | static void destroyArray(ObjectHeader* objectHeader); 39 | 40 | // We use a function to retrieve the destructor map to avoid static initialization ordering issues 41 | DestructorMap& getDestructorMap(); //defined in FRCManager.cpp 42 | 43 | class DestructorMap 44 | { 45 | public: 46 | using Destructor = void(*)(ObjectHeader* header); 47 | 48 | private: 49 | 50 | static constexpr sz initialCapacity = 8192; 51 | 52 | public: 53 | 54 | DestructorMap() 55 | { 56 | destructors.reserve(initialCapacity); 57 | } 58 | 59 | ~DestructorMap() 60 | { 61 | ; 62 | } 63 | 64 | template 65 | static uint getTypeCode() 66 | { 67 | //TODO: investigate better ways of doing this. 68 | static auto const typeCode = getDestructorMap().registerType(); 69 | return typeCode; 70 | } 71 | 72 | template 73 | static uint getArrayTypeCode() 74 | { 75 | //TODO: investigate better ways of doing this. 76 | static auto const typeCode = getTypeCode() + 1; 77 | return typeCode; 78 | } 79 | 80 | static void callDestructor(ObjectHeader* header, uint typeCode) 81 | { 82 | static auto& dm = getDestructorMap(); 83 | 84 | assert(typeCode < dm.destructors.size()); 85 | auto destructor = dm.destructors[typeCode]; 86 | assert(destructor != nullptr); 87 | 88 | destructor(header); 89 | } 90 | 91 | private: 92 | 93 | template 94 | uint registerType() 95 | { 96 | static_assert( 97 | sizeof(T*) == sizeof(void*), 98 | "Type pointer and void pointer must be the same size."); 99 | 100 | std::type_index typeIndex(typeid(T)); 101 | auto iter = typeIDToTypeCodeMap.find(typeIndex); 102 | if(iter != typeIDToTypeCodeMap.end()) 103 | return iter->second; //hit 104 | 105 | //miss 106 | uint typeCode = (uint)destructors.size(); 107 | typeIDToTypeCodeMap.insert(iter, {typeIndex, typeCode}); 108 | destructors.emplace_back(&destroyObject); 109 | destructors.emplace_back(&destroyArray); 110 | 111 | return typeCode; 112 | } 113 | 114 | private: 115 | std::vector destructors; 116 | std::unordered_map typeIDToTypeCodeMap; //TODO: optimize 117 | }; 118 | 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/frc/detail/FRCConstants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FRCConstants.h 3 | * Copyright 2014-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace terrain 20 | { 21 | namespace frc 22 | { 23 | namespace detail 24 | { 25 | 26 | class FRCConstants 27 | { 28 | public: 29 | static constexpr sz pinSetSize = 128; 30 | static constexpr sz protectedBlockSize = 128; //must be pinSetSize 31 | 32 | static constexpr sz logBlockSize = 256; 33 | static constexpr sz logSize = sz(1) << 21; //16 MB 34 | static constexpr sz logBufferSize = sz(1) << 22; //must be a power of two (2MB) 35 | static constexpr sz logMask = logBufferSize - 1; 36 | 37 | static constexpr sz baseHelpInterval = 64; 38 | static constexpr sz maxLogSizeBeforeHelpIntervalReduction = logSize / 2; //logBlockSize * 16; 39 | static constexpr sz maxLogSizeBeforeBlockingHelpCall = logSize - 32 * logBlockSize; 40 | static constexpr float helpIntervalReductionConstant = (logSize - 41 | maxLogSizeBeforeHelpIntervalReduction) / baseHelpInterval; 42 | static constexpr sz numHelpAttemptsBeforeBlocking = 64; 43 | static constexpr sz numTryHelpCallsOnUnregister = 1024; 44 | 45 | static constexpr bool enableSemiDeferredDecrements = false; 46 | static constexpr bool enableCheckedDecrements = false; 47 | 48 | static constexpr sz busySignal = 1; 49 | 50 | static constexpr byte scan = 0; 51 | static constexpr byte sweep = 1; 52 | }; 53 | 54 | } /* namespace detail */ 55 | } /* namespace frc */ 56 | } /* namespace terrain */ 57 | -------------------------------------------------------------------------------- /src/frc/detail/FRCManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FRCManager.cpp 3 | * Copyright 2016-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | #include "FRCManager.h" 19 | #include "ThreadData.h" 20 | #include "../frc.h" 21 | #include 22 | 23 | namespace terrain 24 | { 25 | namespace frc 26 | { 27 | namespace detail 28 | { 29 | 30 | DestructorMap& getDestructorMap() 31 | { 32 | static DestructorMap s_destructorMap; 33 | 34 | return s_destructorMap; 35 | } 36 | 37 | //this is left uninitialized for performance reasons 38 | tls(ThreadData*, threadData); 39 | 40 | //this is used to track recursive registrations 41 | thread_local sz threadDataRegistrationCount = 0; 42 | 43 | FRCManager& getFRCManager() 44 | { 45 | static FRCManager s_manager; 46 | return s_manager; 47 | } 48 | 49 | FRCManager& dummy = getFRCManager(); 50 | 51 | FRCManager::FRCManager() : 52 | helpRouter(2 * hardwareConcurrency()) 53 | { 54 | getDestructorMap(); // we need to make sure the destructorMap has a lifetime that exceeds the FRCManager 55 | writeFence(); 56 | } 57 | 58 | FRCManager::~FRCManager() 59 | { 60 | auto td = registerThread(); 61 | helpRouter.collect(td); 62 | unregisterThread(); 63 | delete td; 64 | } 65 | 66 | ThreadData* FRCManager::registerThread() 67 | { 68 | if(isThreadRegistered()) 69 | { 70 | //already registered 71 | ++threadDataRegistrationCount; 72 | return threadData; 73 | } 74 | 75 | threadData = new ThreadData(); 76 | threadDataRegistrationCount = 1; 77 | 78 | getFRCManager().helpRouter.addThread(threadData); 79 | 80 | if(debug) 81 | dprint("registerThread: %p\n", threadData); 82 | 83 | return threadData; 84 | } 85 | 86 | void FRCManager::unregisterThread() 87 | { 88 | assert(isThreadRegistered()); 89 | 90 | if(threadDataRegistrationCount == 1) 91 | { 92 | auto& manager = getFRCManager(); 93 | for(sz i = 0; i < FRCConstants::numTryHelpCallsOnUnregister; ++i) 94 | manager.help(); 95 | 96 | threadData->detach(); 97 | threadData = nullptr; 98 | } 99 | 100 | --threadDataRegistrationCount; 101 | } 102 | 103 | bool FRCManager::isThreadRegistered() noexcept 104 | { 105 | return threadDataRegistrationCount > 0; 106 | } 107 | 108 | void FRCManager::help() 109 | { 110 | if(!isThreadRegistered()) 111 | return; 112 | threadData->help(); 113 | } 114 | 115 | 116 | void FRCManager::collect() 117 | { 118 | FRCToken token; 119 | getFRCManager().helpRouter.collect(threadData); 120 | } 121 | 122 | bool isThreadRegistered() noexcept 123 | { 124 | return FRCManager::isThreadRegistered(); 125 | } 126 | 127 | } /* namespace detail */ 128 | } /* namespace frc */ 129 | } /* namespace terrain */ 130 | -------------------------------------------------------------------------------- /src/frc/detail/FRCManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FRCManager.h 3 | * Copyright 2014-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include "FRCConstants.h" 22 | #include "ThreadData.h" 23 | #include "DestructorMap.h" 24 | #include "ObjectHeader.h" 25 | #include "HelpRouter.h" 26 | 27 | 28 | namespace terrain 29 | { 30 | namespace frc 31 | { 32 | namespace detail 33 | { 34 | 35 | /** 36 | * this shell class ensures that the map is statically 37 | * initialized before destructors are registered in it. 38 | */ 39 | extern DestructorMap destructorMap; 40 | 41 | class FRCManager; 42 | 43 | 44 | static constexpr bool debug = false; 45 | static constexpr bool debugExtra = false; 46 | 47 | 48 | extern tls(ThreadData*, threadData); 49 | 50 | FRCManager& getFRCManager(); 51 | 52 | class FRCManager 53 | { 54 | private: 55 | static constexpr bool debug = false; 56 | static constexpr bool debugExtra = false; 57 | 58 | public: 59 | FRCManager(); 60 | 61 | FRCManager(FRCManager const&) = delete; 62 | 63 | FRCManager(FRCManager&&) = delete; 64 | 65 | FRCManager& operator=(FRCManager const&) = delete; 66 | 67 | FRCManager& operator=(FRCManager&&) = delete; 68 | 69 | ~FRCManager(); 70 | 71 | void help(); 72 | 73 | public: 74 | 75 | static void collect(); 76 | 77 | static ThreadData* registerThread(); 78 | 79 | static void unregisterThread(); 80 | 81 | static bool isThreadRegistered() noexcept; 82 | 83 | private: 84 | 85 | HelpRouter helpRouter; 86 | }; 87 | 88 | extern bool isThreadRegistered() noexcept; 89 | 90 | } /* namespace detail */ 91 | } /* namespace frc */ 92 | } /* namespace terrain */ 93 | -------------------------------------------------------------------------------- /src/frc/detail/HelpRouter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 Terrain Data, Inc. 3 | * 4 | * This file is part of FRC, a fast reference counting library for C++ 5 | * (see ). 6 | * 7 | * FRC is distributed under the MIT License, which is found in 8 | * COPYING.md in the repository. 9 | * 10 | * You should have received a copy of the MIT License 11 | * along with FRC. If not, see . 12 | */ 13 | 14 | #include 15 | #include 16 | #include "HelpRouter.h" 17 | #include "ThreadData.h" 18 | 19 | namespace terrain 20 | { 21 | namespace frc 22 | { 23 | namespace detail 24 | { 25 | 26 | HelpRouter::HelpRouter(sz numGroups) : 27 | phase(scan), 28 | scanQueue(numGroups), 29 | sweepQueue(numGroups) 30 | { 31 | queues[scan] = &scanQueue; 32 | queues[sweep] = &sweepQueue; 33 | 34 | writeFence(); 35 | } 36 | 37 | HelpRouter::~HelpRouter() 38 | { 39 | ; 40 | } 41 | 42 | void HelpRouter::addThread(ThreadData* td) 43 | { 44 | td->helpRouter = this; 45 | 46 | readFence(); 47 | auto p = phase; 48 | enqueueThread(td, p, oarl); 49 | phaseCV.notify_one(); 50 | 51 | /* This prevents stalls when this is the only queued thread, but it was queued 52 | * to the next phase instead of this phase. This can happen if running threads 53 | * are concurrently leaving the router while this lone thread is being added. 54 | */ 55 | readFence(); 56 | if(phase != p && !queues[phase]->barrier.status(orlx)) 57 | tryAdvancePhase(); 58 | } 59 | 60 | bool HelpRouter::tryHelp(ThreadData* td) 61 | { 62 | return tryHelpSubqueue(phase, td->subqueue) || tryHelp(); 63 | } 64 | 65 | bool HelpRouter::tryHelp() 66 | { 67 | auto p = phase; 68 | auto& queue = *queues[p]; 69 | auto index = queue.router.findAcquired(); 70 | if(index == StaticTreeRouter::notFound) 71 | return false; 72 | 73 | return tryHelpSubqueue(p, index); 74 | } 75 | 76 | bool HelpRouter::tryHelpSubqueue(uint p, uint index) 77 | { 78 | auto& queue = *queues[p]; 79 | auto& subqueue = queue.subqueues[index]; 80 | auto subqueueLock = subqueue.mutex.acquire(); 81 | auto& subqq = subqueue.queue; 82 | if(p != phase || subqq.empty()) 83 | return false; 84 | 85 | auto td = subqq.back(); 86 | bool complete = td->tryHelp( 87 | phase, 88 | [&](bool lastTask) 89 | { 90 | if(lastTask) 91 | { 92 | //thread is done dispatching: dequeue it 93 | if(debug) dout("thread released ", td, " ", phase); 94 | 95 | td->lastPhaseDispatched = p; 96 | while(!subqq.empty() && subqq.back()->lastPhaseDispatched == p) 97 | subqq.pop_back(); 98 | 99 | if(subqq.empty()) 100 | queue.router.release(index); //subqueue empty: release its route 101 | } 102 | 103 | subqueueLock.unlock(); 104 | }); 105 | 106 | if(!complete) 107 | return true; //task finished but thread still has work remaining during this phase 108 | 109 | //thread's work is complete for this phase 110 | if(debug) dout("thread completed ", td, " ", phase); 111 | 112 | bool deleting = (phase == sweep && td->isReadyToDestruct()); 113 | if(!deleting) 114 | { 115 | //enqueue thread in the next phase's queue 116 | auto next = p ^ 1; 117 | enqueueThread(td, next); 118 | } 119 | 120 | 121 | if(subqueue.count.fetch_sub(1, oarl) <= 1) //release subqueue count... 122 | { 123 | if(queue.barrier.release(index)) //subqueue completed: release barrier 124 | { 125 | tryAdvancePhase(); //phase completed: advance to next phase 126 | } 127 | } 128 | 129 | if(deleting) 130 | { 131 | //thread has detached and logs have been processed: delete this ThreadData 132 | if(debug) dout("destructing thread ", td, " ", phase); 133 | delete td; 134 | } 135 | 136 | return true; 137 | } 138 | 139 | void HelpRouter::help(ThreadData* td) 140 | { 141 | if(!tryHelp(td)) 142 | help(); 143 | } 144 | 145 | void HelpRouter::help() 146 | { 147 | for(;;) 148 | { 149 | for(sz i = 0; i < FRCConstants::numHelpAttemptsBeforeBlocking; ++i) 150 | { 151 | if(tryHelp()) 152 | return; 153 | } 154 | 155 | std::unique_lock phaseLock(phaseMutex); 156 | if(queues[phase]->barrier.status(orlx) && !queues[phase]->router.status(orlx)) 157 | { 158 | if(debug) dout("Waiting on phaseCV."); 159 | phaseCV.wait(phaseLock); 160 | } 161 | } 162 | } 163 | 164 | void HelpRouter::collect(ThreadData* td) 165 | { 166 | do 167 | { 168 | for(sz i = 0; i < 2 * 8; ++i) 169 | { 170 | readFence(); 171 | auto start = phase; 172 | do 173 | { 174 | td->help(); 175 | readFence(); 176 | } 177 | while(phase == start); 178 | } 179 | 180 | } 181 | while(!td->allWorkComplete()); 182 | } 183 | 184 | void HelpRouter::enqueueThread(ThreadData* td, uint p, std::memory_order mo) 185 | { 186 | auto& queue = *queues[p]; 187 | auto index = (uint)FastRNG::next(queue.subqueues.size()); 188 | auto& subqueue = queue.subqueues[index]; 189 | 190 | td->lastPhaseDispatched = p ^ 1; 191 | td->subqueue = index; 192 | 193 | auto subqueueLock = subqueue.mutex.acquire(); 194 | 195 | subqueue.queue.push_back(td); 196 | if(subqueue.count.fetch_add(1, mo) == 0) 197 | { 198 | queue.router.acquire(index); 199 | queue.barrier.acquire(index); 200 | } 201 | } 202 | 203 | bool HelpRouter::tryAdvancePhase() 204 | { 205 | { 206 | std::unique_lock phaseLock(phaseMutex); 207 | auto& queue = queues[phase]; 208 | if(queue->barrier.status(orlx)) 209 | return false; // phase not yet completed 210 | 211 | phase ^= 1; //advance phase 212 | } 213 | 214 | phaseCV.notify_all(); 215 | return true; 216 | } 217 | 218 | 219 | 220 | } /* namespace detail */ 221 | } /* namespace frc */ 222 | } /* namespace terrain */ 223 | 224 | -------------------------------------------------------------------------------- /src/frc/detail/HelpRouter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014-2018 Terrain Data, Inc. 3 | * 4 | * This file is part of FRC, a fast reference counting library for C++ 5 | * (see ). 6 | * 7 | * FRC is distributed under the MIT License, which is found in 8 | * COPYING.md in the repository. 9 | * 10 | * You should have received a copy of the MIT License 11 | * along with FRC. If not, see . 12 | */ 13 | 14 | #pragma once 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "FRCConstants.h" 21 | #include "ThreadData.h" 22 | 23 | namespace terrain 24 | { 25 | namespace frc 26 | { 27 | namespace detail 28 | { 29 | 30 | class ThreadData; 31 | 32 | class HelpRouter 33 | { 34 | public: 35 | 36 | HelpRouter(sz numGroups); 37 | 38 | HelpRouter(HelpRouter const&) = delete; 39 | HelpRouter(HelpRouter&&) = delete; 40 | HelpRouter& operator=(HelpRouter const&) = delete; 41 | HelpRouter& operator=(HelpRouter&&) = delete; 42 | 43 | ~HelpRouter(); 44 | 45 | void addThread(ThreadData* td); 46 | bool tryHelp(ThreadData* td); 47 | bool tryHelp(); 48 | void help(ThreadData* td); 49 | void help(); 50 | void collect(ThreadData* td); 51 | 52 | private: 53 | 54 | bool tryHelpSubqueue(uint index, uint p); 55 | void enqueueThread(ThreadData* td, uint p, std::memory_order mo = oarl); 56 | bool tryAdvancePhase(); 57 | 58 | private: 59 | static constexpr auto scan = FRCConstants::scan; 60 | static constexpr auto sweep = FRCConstants::sweep; 61 | 62 | static constexpr bool debug = false; 63 | 64 | struct Subqueue 65 | { 66 | MutexSpin mutex; 67 | std::vector queue; 68 | cacheLinePadding p0; 69 | atm count; //TODO: consider splitting this into a separate atomic var 70 | cacheLinePadding p1; 71 | 72 | Subqueue() : 73 | count(0) 74 | { 75 | ; 76 | } 77 | }; 78 | 79 | struct Queue 80 | { 81 | StaticTreeRouter router; 82 | StaticTreeRouter barrier; 83 | std::vector subqueues; 84 | 85 | explicit Queue(sz numGroups) : 86 | router(numGroups), 87 | barrier(numGroups), 88 | subqueues(numGroups) 89 | { 90 | ; 91 | } 92 | }; 93 | 94 | private: 95 | uint phase; 96 | Queue* queues[2]; 97 | Queue scanQueue, sweepQueue; 98 | 99 | cacheLinePadding p0; 100 | std::mutex phaseMutex; 101 | std::condition_variable phaseCV; 102 | cacheLinePadding p1; 103 | }; 104 | 105 | } /* namespace detail */ 106 | } /* namespace frc */ 107 | } /* namespace terrain */ 108 | -------------------------------------------------------------------------------- /src/frc/detail/PinSet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014, 2017 Terrain Data, Inc. 3 | * 4 | * This file is part of FRC, a fast reference counting library for C++ 5 | * (see ). 6 | * 7 | * FRC is distributed under the MIT License, which is found in 8 | * COPYING.md in the repository. 9 | * 10 | * You should have received a copy of the MIT License 11 | * along with FRC. If not, see . 12 | */ 13 | 14 | #include "PinSet.h" 15 | 16 | namespace terrain 17 | { 18 | namespace frc 19 | { 20 | namespace detail 21 | { 22 | 23 | tls(atm*, head); 24 | 25 | PinSet::PinSet() : 26 | protectedObjects(new atm[size]) 27 | { 28 | for(sz i = 0; i < (size - 1); ++i) 29 | protectedObjects[i].store(&protectedObjects[i + 1], orlx); 30 | protectedObjects[size - 1].store(nullptr, orls); 31 | 32 | head = &protectedObjects[0]; 33 | } 34 | 35 | 36 | } /* namespace detail */ 37 | } /* namespace frc */ 38 | } /* namespace terrain */ 39 | 40 | -------------------------------------------------------------------------------- /src/frc/detail/PinSet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: PinSet.h 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "FRCConstants.h" 22 | 23 | namespace terrain 24 | { 25 | namespace frc 26 | { 27 | namespace detail 28 | { 29 | 30 | extern tls(atm*, head); 31 | 32 | extern bool isThreadRegistered() noexcept; 33 | 34 | class PinSet 35 | { 36 | private: 37 | static sz constexpr size = FRCConstants::pinSetSize; 38 | 39 | public: 40 | 41 | PinSet(); 42 | 43 | /** 44 | * acquires a pin 45 | */ 46 | static atm* acquire() noexcept 47 | { 48 | assert(isThreadRegistered()); 49 | assert(head != nullptr); // all pins acquired 50 | 51 | auto value = head; 52 | auto next = (atm*) value->load(orlx); 53 | head = next; 54 | return value; 55 | } 56 | 57 | /** 58 | * releases a pin 59 | */ 60 | static void release(atm* value) noexcept 61 | { 62 | assert(isThreadRegistered()); 63 | 64 | auto next = head; 65 | value->store(next, orlx); 66 | head = value; 67 | } 68 | 69 | static void setProtectedPointer(atm* value) noexcept 70 | { 71 | head = value; 72 | } 73 | 74 | static auto getProtectedPointer() noexcept 75 | { 76 | return head; 77 | } 78 | 79 | bool isValid(void* ptr) noexcept 80 | { 81 | return ptr != nullptr && 82 | ((sz) ptr < (sz) &protectedObjects[0] || 83 | (sz) ptr >= (sz) &protectedObjects[size]); 84 | } 85 | 86 | public: 87 | std::unique_ptr[]> protectedObjects; 88 | }; 89 | 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/frc/detail/ThreadData.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ThreadData.cpp 3 | * Copyright 2016-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | 16 | #include "ThreadData.h" 17 | #include "HelpRouter.h" 18 | 19 | namespace terrain 20 | { 21 | namespace frc 22 | { 23 | namespace detail 24 | { 25 | 26 | 27 | tls(ScanFlag, scanFlag); 28 | 29 | 30 | ThreadData::ThreadData() : 31 | decrementIndex(0), 32 | helpIndex(FRCConstants::baseHelpInterval), 33 | decrementBuffer(new ObjectHeader * [FRCConstants::logBufferSize]), 34 | helping(false), 35 | lastHelpIndex(0), 36 | lastScanIndex(0), 37 | decrementConsumerIndex(0), 38 | decrementCaptureIndex(0), 39 | decrementStackIndex(0), 40 | decrementStackTarget(0), 41 | numRemainingDecrementBlocks(-1), 42 | numRemainingScanBlocks(numScanBlocks), 43 | detached(false), 44 | helpRouter(nullptr) 45 | { 46 | scanFlag.flag.store(false, orls); 47 | decrementStack.reserve(FRCConstants::logSize); 48 | } 49 | 50 | ThreadData::~ThreadData() 51 | { 52 | ; 53 | } 54 | 55 | void ThreadData::help() 56 | { 57 | decrementIndex &= FRCConstants::logMask; //wrap log index 58 | writeFence(); 59 | lastHelpIndex.store(decrementIndex, orls); 60 | 61 | //don't recursively help 62 | if(helping) 63 | { 64 | if(debug) dout("ThreadData::help() ", this, " recursive help ", helpIndex); 65 | return; 66 | } 67 | 68 | helpIndex = FRCConstants::logBufferSize; 69 | helping = true; 70 | // for (;;) 71 | // { 72 | if(decrementStackIndex + bufferSeparation(decrementCaptureIndex, decrementIndex) 73 | <= FRCConstants::maxLogSizeBeforeBlockingHelpCall) 74 | { 75 | helpRouter->tryHelp(this); 76 | } 77 | else 78 | { 79 | helpRouter->help(this); 80 | } 81 | 82 | 83 | //make help interval shrink as the buffer grows 84 | auto helpInterval = FRCConstants::baseHelpInterval; 85 | auto bufferUsed = bufferSeparation(decrementCaptureIndex, decrementIndex); 86 | auto logUsed = decrementStackIndex + bufferUsed; 87 | if(logUsed > FRCConstants::maxLogSizeBeforeHelpIntervalReduction) 88 | { 89 | /* Exponentially decrease help interval past this point to exert increasing 90 | * back-pressure on log processing. Closed-loop feedback control. 91 | */ 92 | 93 | auto excessUsage = logUsed - FRCConstants::maxLogSizeBeforeHelpIntervalReduction; 94 | auto excess = 1 + excessUsage / FRCConstants::helpIntervalReductionConstant; 95 | helpInterval = std::max((sz)1, (sz)(helpInterval / excess)); 96 | } 97 | 98 | // if (helpInterval < 1) 99 | // continue; 100 | 101 | assert(helpInterval < (FRCConstants::logBufferSize - bufferUsed)); // buffer overflow 102 | helpIndex = std::min(FRCConstants::logBufferSize, decrementIndex + helpInterval); 103 | helping = false; 104 | 105 | if(debug) dout("ThreadData::help() ", this, " ", helpInterval, " ", bufferUsed); 106 | if(debug && helpInterval <= 2) 107 | dout("ThreadData::help() ", this, " ", 108 | helpInterval, " ", decrementStackIndex, " ", 109 | logUsed - decrementStackIndex, " ", logUsed); 110 | // break; 111 | // } 112 | 113 | 114 | } 115 | 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/frc/frc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: frc.h 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "detail/FRCManager.h" 18 | 19 | #include "AtomicPointer.h" 20 | #include "SharedPointer.h" 21 | #include "PrivatePointer.h" 22 | 23 | namespace terrain 24 | { 25 | namespace frc 26 | { 27 | 28 | 29 | template 30 | using ap = AtomicPointer; 31 | 32 | template 33 | using sp = SharedPointer; 34 | 35 | template 36 | using hp = PrivatePointer; 37 | 38 | inline static bool isThreadRegistered() 39 | { 40 | return detail::FRCManager::isThreadRegistered(); 41 | } 42 | 43 | /** 44 | * A wrapper class for use when entering and exiting FRC code. 45 | * Just stack allocate a FRCToken, which will register the thread. 46 | * When the token goes out of scope, it will be destructed, thus 47 | * unregistering the thread. 48 | */ 49 | struct FRCToken 50 | { 51 | 52 | FRCToken() 53 | { 54 | detail::FRCManager::registerThread(); 55 | } 56 | 57 | FRCToken(FRCToken const&) = delete; 58 | FRCToken(FRCToken&&) = delete; 59 | FRCToken& operator=(FRCToken const&) = delete; 60 | FRCToken& operator=(FRCToken&&) = delete; 61 | 62 | ~FRCToken() 63 | { 64 | detail::FRCManager::unregisterThread(); 65 | } 66 | }; 67 | 68 | template 69 | auto make_atomic(Args&& ... args) 70 | { 71 | ap result; 72 | result.makeProtected(std::forward(args) ...); 73 | return result; 74 | } 75 | 76 | template 77 | auto make_shared(Args&& ... args) 78 | { 79 | sp result; 80 | result.make(std::forward(args) ...); 81 | return result; 82 | } 83 | 84 | template 85 | auto make_protected(Args&& ... args) 86 | { 87 | hp result; 88 | result.make(std::forward(args)...); 89 | return result; 90 | } 91 | 92 | } /* namespace frc */ 93 | 94 | } /* namespace terrain */ 95 | -------------------------------------------------------------------------------- /src/synchronization/MutexSpin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: MutexSpin.h 3 | * Copyright 2013-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include "Spinner.h" 21 | 22 | namespace terrain 23 | { 24 | 25 | /** 26 | * A exponentially backed off spinlock with low overhead when uncontended. 27 | * Uses random jitter to reduce rematch problems when contended. 28 | */ 29 | class MutexSpin 30 | { 31 | private: 32 | static constexpr sz maxSpins = 2048 - 1; 33 | 34 | public: 35 | 36 | constexpr MutexSpin() noexcept 37 | : locked(false) 38 | { 39 | //locked.store(false, orls); 40 | } 41 | 42 | MutexSpin(MutexSpin const&) = delete; 43 | 44 | MutexSpin(MutexSpin&&) = delete; 45 | 46 | void lock() noexcept 47 | { 48 | if(!locked.exchange(true, oarl)) 49 | return; 50 | 51 | slowLock(); 52 | } 53 | 54 | bool try_lock() noexcept 55 | { 56 | return !locked.load(ocon) && !locked.exchange(true, oarl); 57 | } 58 | 59 | void unlock() noexcept 60 | { 61 | locked.store(false, orls); 62 | } 63 | 64 | auto acquire() 65 | { 66 | return std::unique_lock(*this); 67 | } 68 | 69 | auto try_acquire() 70 | { 71 | return std::unique_lock(*this, std::try_to_lock); 72 | } 73 | 74 | private: 75 | 76 | void slowLock() noexcept 77 | { 78 | if(Spinner::spin( 79 | [&]() 80 | { 81 | return try_lock(); 82 | }, 83 | 1024 * 128)) 84 | return; 85 | 86 | while(!try_lock()) 87 | std::this_thread::yield(); 88 | } 89 | 90 | private: 91 | atm locked; 92 | }; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/synchronization/Relaxer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Relaxer.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace terrain 19 | { 20 | 21 | /** 22 | * 23 | */ 24 | struct Relaxer 25 | { 26 | public: 27 | 28 | #ifdef TERRAIN_X64 29 | static void relax() noexcept 30 | { 31 | //low power pause instruction 32 | asm volatile("pause;": : :); 33 | } 34 | #else 35 | static void relax() noexcept 36 | { 37 | } 38 | #endif 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/synchronization/Spinner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Spinner.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "Relaxer.h" 20 | 21 | namespace terrain 22 | { 23 | 24 | struct Spinner 25 | { 26 | 27 | template 28 | static bool spin(TryFunction tryFunc, sz const maxSpins) 29 | { 30 | //exponential back-off with jitter 31 | sz totalSpins = 0; 32 | for(sz base = 32;;) 33 | { 34 | sz numSpins = FastRNG::next(base); 35 | for(volatile sz j = numSpins; j > 0; --j) 36 | Relaxer::relax(); 37 | 38 | if(tryFunc()) 39 | return true; 40 | 41 | totalSpins += numSpins; 42 | 43 | base *= 4; 44 | if(totalSpins + base / 2 >= maxSpins) 45 | break; 46 | } 47 | 48 | return false; 49 | } 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/synchronization/StaticTreeRouter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: StaticTreeRouter.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "StaticTreeRouter.h" 21 | 22 | namespace terrain 23 | { 24 | 25 | StaticTreeRouter::StaticTreeRouter(uint numInputs) 26 | { 27 | this->numInputs = numInputs; 28 | numNodes = roundUpToPowerOfTwo(std::max(uint(2), numInputs)); 29 | nodes.reset(new INode[numNodes]); 30 | writeFence(); 31 | } 32 | 33 | bool StaticTreeRouter::valid() const noexcept 34 | { 35 | readFence(); 36 | uint code = 3 & nodes[rootIndex]->status; 37 | bool root_empty = code == 0; 38 | 39 | for(uint i = 0; i < numInputs; i += 2) 40 | { 41 | auto index = getParentIndex(getInputIndex(i)); 42 | for(;;) 43 | { 44 | if((3 & (nodes[index]->status)) > 0) 45 | if(root_empty && index != rootIndex) 46 | return false; 47 | 48 | if(((index & 1) != 0) || index <= rootIndex) 49 | break; 50 | index = getParentIndex(index); 51 | } 52 | } 53 | return true; 54 | } 55 | 56 | uint StaticTreeRouter::getParentIndex(uint index) noexcept 57 | { 58 | return index / 2; 59 | } 60 | 61 | uint StaticTreeRouter::getLeftChildIndex(uint index) noexcept 62 | { 63 | return index * 2; 64 | } 65 | 66 | uint StaticTreeRouter::getRightChildIndex(uint index) noexcept 67 | { 68 | return getLeftChildIndex(index) + 1; 69 | } 70 | 71 | uint StaticTreeRouter::getInputIndex(uint index) const noexcept 72 | { 73 | return index + numNodes; 74 | } 75 | 76 | /** 77 | * even numbers are left children 78 | */ 79 | uint StaticTreeRouter::getMask(uint index) noexcept 80 | { 81 | return (index & 1) + 1; 82 | } 83 | 84 | uint StaticTreeRouter::getSiblingIndex(uint index) noexcept 85 | { 86 | return index ^ 1; 87 | } 88 | 89 | bool StaticTreeRouter::cyclicRelease(uint index) noexcept 90 | { 91 | return doCyclicRelease(getInputIndex(index)); 92 | } 93 | 94 | bool StaticTreeRouter::doCyclicRelease(uint childIndex) noexcept 95 | { 96 | auto parentIndex = getParentIndex(childIndex); 97 | auto mask = getMask(childIndex); 98 | Node& node = nodes[parentIndex].get(); 99 | 100 | auto guard = node.lock.acquire(); 101 | node.status ^= mask; // toggle mask bit 102 | 103 | if(node.status == 1 || node.status == 2) 104 | return false; //stop propagating signal 105 | 106 | if(parentIndex > rootIndex) 107 | doRelease(parentIndex); 108 | return true; //root was cycled 109 | } 110 | 111 | bool StaticTreeRouter::release(uint index) noexcept 112 | { 113 | return doRelease(getInputIndex(index)); 114 | } 115 | 116 | bool StaticTreeRouter::doRelease(uint childIndex) noexcept 117 | { 118 | auto parentIndex = getParentIndex(childIndex); 119 | auto mask = getMask(childIndex); 120 | Node& node = nodes[parentIndex].get(); 121 | 122 | auto guard = node.lock.acquire(); 123 | 124 | if((node.status & mask) == 0) 125 | return false; //already cleared 126 | 127 | node.status &= ~mask; 128 | 129 | if(node.status != 0) 130 | return false; //stop propagating signal 131 | 132 | if(parentIndex <= rootIndex) 133 | return true; //root status became zero 134 | 135 | return doRelease(parentIndex); 136 | } 137 | 138 | bool StaticTreeRouter::acquire(uint index) noexcept 139 | { 140 | return doAcquire(getInputIndex(index)); 141 | } 142 | 143 | bool StaticTreeRouter::doAcquire(uint childIndex) noexcept 144 | { 145 | auto parentIndex = getParentIndex(childIndex); 146 | auto mask = getMask(childIndex); 147 | Node& node = nodes[parentIndex].get(); 148 | 149 | auto guard = node.lock.acquire(); 150 | 151 | if((node.status & mask) != 0) 152 | return false; //already acquired 153 | 154 | auto prev = node.status; 155 | node.status |= mask; 156 | 157 | if(parentIndex <= rootIndex) 158 | return (prev == 0); //root status became non-zero 159 | 160 | return doAcquire(parentIndex); 161 | } 162 | 163 | uint StaticTreeRouter::findAcquired(std::memory_order mo) const noexcept 164 | { 165 | do 166 | { 167 | auto result = tryFindAcquired(mo); 168 | if(result != notFound) 169 | return result; 170 | } 171 | while(status(oacq)); 172 | 173 | return notFound; 174 | } 175 | 176 | uint StaticTreeRouter::tryFindAcquired(std::memory_order mo) const noexcept 177 | { 178 | std::atomic_thread_fence(mo); 179 | uint salt = FastRNG::next(); 180 | uint index = rootIndex; 181 | for(;;) 182 | { 183 | if(index >= numNodes) 184 | { 185 | return index - numNodes; 186 | } 187 | 188 | uint code = 3 & nodes[index]->status; 189 | index = getLeftChildIndex(index); 190 | switch(code) 191 | { 192 | case(0): //empty 193 | return notFound; 194 | 195 | case(1): //left 196 | break; 197 | 198 | case(2): //right 199 | ++index; 200 | break; 201 | 202 | case(3): //both 203 | default: 204 | index += (salt & 1); 205 | salt /= 2; 206 | break; 207 | } 208 | } 209 | } 210 | 211 | void StaticTreeRouter::print() const 212 | { 213 | for(uint i = 0; i < numInputs; i += 2) 214 | { 215 | auto index = getParentIndex(getInputIndex(i)); 216 | for(;;) 217 | { 218 | dprint("%llu ", nodes[index]->status); 219 | 220 | if(((index & 1) != 0) || index <= rootIndex) 221 | break; 222 | index = getParentIndex(index); 223 | } 224 | 225 | dprint("\n"); 226 | } 227 | } 228 | 229 | 230 | } /* namespace terrain */ 231 | -------------------------------------------------------------------------------- /src/synchronization/StaticTreeRouter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: StaticTreeRouter.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | #include "MutexSpin.h" 20 | 21 | namespace terrain 22 | { 23 | 24 | class StaticTreeRouter 25 | { 26 | private: 27 | 28 | struct Node 29 | { 30 | MutexSpin lock; 31 | 32 | /* [left child status | right child status] 33 | * status bit = 0 -> released 34 | * status bit = 1 -> acquired 35 | * 36 | * status = 0 -> both children released 37 | * status = 1 -> left child acquired 38 | * status = 2 -> right child acquired 39 | * status = 3 -> both children acquired 40 | */ 41 | uint status = 0; 42 | }; 43 | 44 | using INode = Isolate; 45 | static constexpr uint rootIndex = 1; 46 | 47 | public: 48 | static constexpr uint notFound = ~uint(0); 49 | 50 | public: 51 | explicit StaticTreeRouter(uint numInputs); 52 | 53 | ~StaticTreeRouter() { }; 54 | 55 | uint getNumInputs() const noexcept 56 | { 57 | return numInputs; 58 | } 59 | 60 | bool valid() const noexcept; 61 | bool cyclicRelease(uint index) noexcept; 62 | bool release(uint index) noexcept; 63 | bool acquire(uint index) noexcept; 64 | uint findAcquired(std::memory_order mo = oacq) const noexcept; 65 | uint tryFindAcquired(std::memory_order mo = oacq) const noexcept; 66 | 67 | bool status(std::memory_order mo = oacq) const noexcept 68 | { 69 | std::atomic_thread_fence(mo); 70 | return nodes[rootIndex]->status; 71 | } 72 | 73 | bool status(uint index, std::memory_order mo = oacq) const noexcept 74 | { 75 | auto inputIndex = getInputIndex(index); 76 | auto mask = getMask(inputIndex); 77 | auto& node = nodes[getParentIndex(inputIndex)]; 78 | 79 | std::atomic_thread_fence(mo); 80 | return node->status & mask; 81 | } 82 | 83 | void print() const; 84 | 85 | private: 86 | 87 | bool doCyclicRelease(uint childIndex) noexcept; 88 | bool doRelease(uint childIndex) noexcept; 89 | bool doAcquire(uint childIndex) noexcept; 90 | uint getInputIndex(uint index) const noexcept; 91 | static uint getParentIndex(uint index) noexcept; 92 | static uint getLeftChildIndex(uint index) noexcept; 93 | static uint getRightChildIndex(uint index) noexcept; 94 | static uint getMask(uint index) noexcept; 95 | static uint getSiblingIndex(uint index) noexcept; 96 | 97 | private: 98 | 99 | std::unique_ptr nodes; 100 | uint numNodes; 101 | uint numInputs; 102 | }; 103 | 104 | } /* namespace terrain */ 105 | -------------------------------------------------------------------------------- /src/util/DebugPrintf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DebugPrintf.cpp 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "util.h" 24 | 25 | namespace terrain 26 | { 27 | 28 | void dprint(char const* message, ...) 29 | { 30 | sz const bufferLength = 4096; 31 | sz const maxLength = bufferLength - sizeof(char); 32 | char buffer[bufferLength]; 33 | 34 | va_list argptr; 35 | va_start(argptr, message); 36 | vsnprintf(buffer, maxLength, message, argptr); 37 | va_end(argptr); 38 | 39 | std::cout << buffer; 40 | } 41 | 42 | void dprint(string s) 43 | { 44 | std::cout << s; 45 | } 46 | 47 | } /* namespace terrain */ 48 | -------------------------------------------------------------------------------- /src/util/DebugPrintf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: DebugPrintf.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "types.h" 18 | #include "toStringStream.h" 19 | 20 | 21 | namespace terrain 22 | { 23 | 24 | /** 25 | * A command line debug print utility function 26 | */ 27 | 28 | /** 29 | * prints a debug message 30 | * @param message sprintf formatted message string 31 | * @param ... any values to place in the message (sprintf format) 32 | */ 33 | extern void dprint(char const* message, ...); 34 | 35 | /** 36 | * prints a debug message 37 | * @param s message to print 38 | */ 39 | extern void dprint(string s); 40 | 41 | template 42 | static inline void dout(Args ... args) 43 | { 44 | dprint(toStringStream(args..., "\n").str()); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/util/Exception.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Exception.cpp 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | #include "Exception.h" 19 | 20 | namespace terrain 21 | { 22 | 23 | Exception::Exception(const char* description, ...) 24 | { 25 | sz const maxLength = 4096 - sizeof(sz) * 2; 26 | char buffer[maxLength]; 27 | 28 | va_list argptr; 29 | va_start(argptr, description); 30 | vsnprintf(buffer, maxLength, description, argptr); 31 | va_end(argptr); 32 | this->description = string(buffer); 33 | } 34 | 35 | Exception::Exception(string description) : 36 | description(std::move(description)) 37 | { 38 | } 39 | 40 | Exception::Exception() 41 | { 42 | } 43 | 44 | Exception::~Exception() noexcept 45 | { 46 | } 47 | 48 | string const& Exception::getDescription() const 49 | { 50 | return description; 51 | } 52 | 53 | void Exception::setDescription(string& s) 54 | { 55 | description = s; 56 | } 57 | 58 | } // namespace terrain 59 | -------------------------------------------------------------------------------- /src/util/Exception.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Exception.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "types.h" 20 | #include 21 | #include 22 | #include 23 | 24 | namespace terrain 25 | { 26 | 27 | /** 28 | * Implements an Exception that stores its message as a string. 29 | */ 30 | class Exception 31 | { 32 | private: 33 | string description; 34 | 35 | public: 36 | /** 37 | * Deprecated 38 | */ 39 | explicit Exception(const char* description, ...); 40 | 41 | explicit Exception(string description); 42 | 43 | template 44 | explicit Exception(Arg&& arg, Args&& ... args) 45 | { 46 | std::stringstream s; 47 | append(s, arg, args...); 48 | setDescription(s); 49 | } 50 | 51 | Exception(Exception&& source) = default; 52 | Exception(Exception const& source) = default; 53 | Exception& operator=(Exception&& source) = delete; 54 | Exception& operator=(Exception const& source) = delete; 55 | 56 | protected: 57 | explicit Exception(); 58 | 59 | public: 60 | virtual ~Exception() noexcept; 61 | 62 | virtual string const& getDescription() const; 63 | 64 | /** 65 | * @return cstring description of this exception 66 | */ 67 | const char* what() const noexcept 68 | { 69 | return this->getDescription().c_str(); 70 | } 71 | protected: 72 | void setDescription(string& s); 73 | 74 | template 75 | void setDescription(T& s) 76 | { 77 | description = s; 78 | } 79 | 80 | void setDescription(std::stringstream& s) 81 | { 82 | description = s.str(); 83 | } 84 | 85 | 86 | protected: 87 | 88 | template 89 | static void append(std::stringstream& s, Arg arg, Args ... args) 90 | { 91 | s << arg; 92 | append(s, args...); 93 | } 94 | 95 | static void append(std::stringstream& s) { } 96 | }; 97 | 98 | } // namespace terrain 99 | -------------------------------------------------------------------------------- /src/util/FastRNG.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FastRNG.cpp 3 | * Copyright 2017-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include "FastRNG.h" 16 | #include "getticks.h" 17 | 18 | namespace terrain 19 | { 20 | 21 | namespace detail 22 | { 23 | tls(un, fastRNGSeeds); 24 | } 25 | 26 | un FastRNG::seed() 27 | { 28 | return seed((un)getticks()); 29 | } 30 | 31 | } // namespace terrain 32 | -------------------------------------------------------------------------------- /src/util/FastRNG.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FastRNG.h 3 | * Copyright 2017-2018 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include "types.h" 19 | #include "tls.h" 20 | #include 21 | 22 | namespace terrain 23 | { 24 | 25 | //http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor 26 | //http://en.wikipedia.org/wiki/Linear_congruential_generator 27 | 28 | class FastRNG; 29 | 30 | namespace detail 31 | { 32 | extern tls(un, fastRNGSeeds); 33 | } 34 | 35 | using namespace detail; 36 | 37 | /** 38 | * A fast, thread-local random number generator. 39 | * Using a fast LCG generator and therefore does not have ideal properties 40 | * for an RNG. Uniform distributions and inter-sample independence is traded off 41 | * here somewhat to achieve high efficiency. Use another RNG if you need 42 | * high quality samples. If you need performance, you came to the right place. 43 | */ 44 | class FastRNG 45 | { 46 | private: 47 | 48 | inline static un getNext() 49 | { 50 | un seed_ = (6364136223846793005ll * fastRNGSeeds 51 | + 1442695040888963407ll); 52 | fastRNGSeeds = seed_; 53 | return (seed_ >> 16ll) ^ (seed_ << (63ll - 16ll)); 54 | } 55 | 56 | inline static un getNext(un max) 57 | { 58 | return getNext() % max; 59 | } 60 | 61 | public: 62 | 63 | static un seed(); 64 | 65 | static un seed(un value) 66 | { 67 | return fastRNGSeeds = value; 68 | } 69 | 70 | /** 71 | * @return next pseudo-uniformly pseudo-randomly generated number integer from [0, std::numeric_limits::max()) 72 | */ 73 | inline static un next() 74 | { 75 | return getNext(); 76 | } 77 | 78 | /** 79 | * @return next pseudo-uniformly pseudo-randomly generated integer from [0, max) 80 | */ 81 | inline static un next(un max) 82 | { 83 | return getNext(max); 84 | } 85 | 86 | /** 87 | * @return next pseudo-uniformly pseudo-randomly generated integer from [min, max) 88 | */ 89 | inline static un next(un min, un max) 90 | { 91 | return min + getNext(max - min); 92 | } 93 | 94 | /** 95 | * @return next pseudo-uniformly pseudo-randomly generated number integer from [0, std::numeric_limits::max()) 96 | */ 97 | inline static uint nextUInt() 98 | { 99 | return (uint)next(); 100 | } 101 | 102 | /** 103 | * @return next pseudo-uniformly pseudo-randomly generated integer from [0, max) 104 | */ 105 | inline static uint nextUInt(uint max) 106 | { 107 | return (uint)next(max); 108 | } 109 | 110 | /** 111 | * @return next pseudo-uniformly pseudo-randomly generated integer from [min, max) 112 | */ 113 | inline static uint nextUInt(uint min, uint max) 114 | { 115 | return (uint)getNext(max - min); 116 | } 117 | }; 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/util/Isolate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: Isolate.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "atomic.h" 18 | 19 | 20 | namespace terrain 21 | { 22 | 23 | /** 24 | * A wrapper for padding an element out to consume an integral number of 25 | * cache lines. This can be used to reduce false-sharing between data 26 | * members when they are being concurrently accessed by more than one 27 | * processor. 28 | * 29 | * Presents a pointer-like interface to the member, as well as a 30 | * get() function which returns a reference to the wrapped element. 31 | */ 32 | template 33 | class Isolate 34 | { 35 | private: 36 | 37 | static constexpr sz cacheLinesPerElement = (sizeof(T) / cacheLineSize); 38 | static constexpr sz paddingSize = cacheLineSize 39 | - (sizeof(T) - (cacheLineSize* cacheLinesPerElement)); 40 | 41 | private: 42 | T element; 43 | byte buffer[paddingSize]; 44 | 45 | public: 46 | 47 | template 48 | inline Isolate(Args&& ... args) 49 | : 50 | element(args...) { } 51 | 52 | inline ~Isolate() { } 53 | 54 | T& get() 55 | { 56 | return element; 57 | } 58 | 59 | inline T* operator->() 60 | { 61 | return &element; 62 | } 63 | 64 | inline T& operator*() 65 | { 66 | return element; 67 | } 68 | 69 | inline T* asPtr() 70 | { 71 | return &element; 72 | } 73 | }; 74 | 75 | template 76 | using AIsolate = Isolate>; 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/util/atomic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: atmomic.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include "types.h" 20 | 21 | /** 22 | * Shortcuts and aliases for writing concurrent, atomic memory accesses. 23 | * Fences and cache line sizing. 24 | */ 25 | namespace terrain 26 | { 27 | 28 | /** 29 | * Cache line size (true for modern Intel processors) 30 | */ 31 | constexpr sz cacheLineSize = 64; //64 byte cache line (Core and newer) 32 | 33 | /** 34 | * Memory order aliases 35 | */ 36 | 37 | const std::memory_order orlx = std::memory_order_relaxed; 38 | const std::memory_order ocon = std::memory_order_consume; 39 | const std::memory_order oacq = std::memory_order_acquire; 40 | const std::memory_order orls = std::memory_order_release; 41 | const std::memory_order oarl = std::memory_order_acq_rel; 42 | const std::memory_order oseq = std::memory_order_seq_cst; 43 | 44 | /** 45 | * A write fence (release memory order) 46 | */ 47 | inline void writeFence() 48 | { 49 | std::atomic_thread_fence(orls); 50 | } 51 | 52 | /** 53 | * A consume fence (consume memory order) 54 | */ 55 | inline void consumeFence() 56 | { 57 | std::atomic_thread_fence(ocon); 58 | } 59 | 60 | /** 61 | * A read fence (acquire memory order) 62 | */ 63 | inline void readFence() 64 | { 65 | std::atomic_thread_fence(oacq); 66 | } 67 | 68 | /** 69 | * A read-write fence (acquire-release memory order) 70 | */ 71 | inline void rwfence() 72 | { 73 | std::atomic_thread_fence(oarl); 74 | } 75 | 76 | /** 77 | * A full memory fence (sequential memory order) 78 | */ 79 | inline void fence() 80 | { 81 | std::atomic_thread_fence(oseq); 82 | } 83 | 84 | /** 85 | * A class which is the size of a cache line. 86 | */ 87 | struct cacheLinePadding 88 | { 89 | char padding[cacheLineSize - 1]; 90 | }; 91 | 92 | /** 93 | * Template alias for std::atomic 94 | */ 95 | template 96 | using atm = std::atomic; 97 | 98 | typedef std::memory_order memoryOrder; 99 | 100 | } 101 | 102 | #include "Isolate.h" 103 | -------------------------------------------------------------------------------- /src/util/defs.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: defs.hpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | /** 18 | * Includes all of the common ctools/util headers 19 | */ 20 | 21 | #include "atomic.h" 22 | #include "types.h" 23 | #include "thread.h" 24 | #include "tls.h" 25 | #include "bitTricks.h" 26 | 27 | using namespace terrain; 28 | -------------------------------------------------------------------------------- /src/util/directives.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: directives.h 3 | * Copyright 2015, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | /** 18 | * Defines several compiler directives for supporting compilers 19 | */ 20 | 21 | #include "platformSpecific.h" 22 | 23 | /** 24 | * The restrict directive lets the compiler make optimizations to memory 25 | * accesses by assuming that no other pointer accesses in the same scope 26 | * write to memory accessed by dereferencing this pointer. 27 | * 28 | * Essentially the same as the C keyword restrict. 29 | * 30 | * see: https://gcc.gnu.org/onlinedocs/gcc/Restricted-Pointers.html 31 | */ 32 | 33 | #ifndef __cplusplus 34 | #define restrict_ restrict 35 | #elif defined(TERRAIN_MSVC) 36 | #define restrict_ __restrict 37 | #elif defined(TERRAIN_GCC) 38 | #define restrict_ __restrict__ 39 | #else 40 | #define restrict_ 41 | #endif 42 | 43 | /** 44 | * Don't use these 45 | */ 46 | #if defined(TERRAIN_MSVC) 47 | #define assume_aligned_(x,alignment) 48 | #define aligned_(alignment) __declspec( align( alignment ) ) 49 | #elif defined(TERRAIN_GCC) 50 | #define assume_aligned_(x,alignment) __builtin_assume_aligned(x,alignment,0) 51 | #define aligned_(alignment) __attribute__ ((__aligned__(alignment))) 52 | #else 53 | #define assume_aligned_(x,alignment) 54 | #define aligned_(alignment) 55 | #endif 56 | 57 | 58 | #undef unlikely 59 | #undef likely 60 | 61 | /** 62 | * These hints can be used to tell the compiler a condition is very likely 63 | * or unlikely to be true. Don't use this without performance testing, and 64 | * only when it makes a big, useful different. Generally the expectation 65 | * needs to be true 9999 out of 10000 times before this is faster than without 66 | * the hint. 67 | */ 68 | #if defined(TERRAIN_GCC) 69 | #define likely(x) __builtin_expect(!!(x), 1) 70 | #define unlikely(x) __builtin_expect(!!(x), 0) 71 | #else 72 | #define likely(expr) (expr) 73 | #define unlikely(expr) (expr) 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /src/util/platformSpecific.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: platformSpecific.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | /** 18 | * This header sets several preprocessor directives used throughout CTools to 19 | * conditionally compile compiler or machine specific code. 20 | */ 21 | 22 | //processor types 23 | #if defined __x86_64__ //&& defined __MMX__ && defined __SSE__ && defined __SSE2__ && defined __SSE3__ && defined __SSE4_2__ 24 | #define TERRAIN_X64 25 | #define TERRAIN_LITTLE_ENDIAN 26 | #else 27 | #error "Target processor not supported." 28 | #endif 29 | 30 | //compilers 31 | #if defined __GNUG__ 32 | #define TERRAIN_GCC 33 | #elif defined _MSC_VER 34 | #define TERRAIN_MSVC 35 | #else 36 | #error "Compiler not Supported." 37 | #endif 38 | 39 | //platforms 40 | //#if ((defined _WIN32) )//|| (defined __CYGWIN__) || (defined __MINGW32__)) 41 | #ifdef _WIN32 42 | #define TERRAIN_WINDOWS 43 | #elif defined __FreeBSD__ 44 | #define TERRAIN_FREEBSD 45 | #elif defined __linux__ 46 | #define TERRAIN_LINUX 47 | #else 48 | #error "Platform not Supported." 49 | #endif 50 | 51 | //compiler x platform combinations 52 | #if defined TERRAIN_GCC 53 | #ifdef TERRAIN_WINDOWS 54 | #define TERRAIN_WINDOWSGCCx64 55 | // #define NTDDI_VERSION NTDDI_VISTA 56 | #elif defined TERRAIN_FREEBSD 57 | #define TERRAIN_BSDGCCx64 58 | #elif defined TERRAIN_LINUX 59 | #define TERRAIN_LINUXGCCx64 60 | #endif 61 | #else 62 | #error "(Compiler, Platform) combination not Supported." 63 | #endif 64 | -------------------------------------------------------------------------------- /src/util/thread.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: thread.cpp 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include "platformSpecific.h" 17 | #include "thread.h" 18 | 19 | 20 | 21 | #if defined(__APPLE__) 22 | #include 23 | 24 | #elif defined(TERRAIN_WINDOWS) 25 | #include 26 | #include 27 | #include 28 | 29 | #elif defined(TERRAIN_LINUX) 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #elif defined(TERRAIN_FREEBSD) 36 | #include 37 | #include 38 | #include 39 | 40 | #else 41 | #error "Unrecognized platform" 42 | #endif 43 | 44 | namespace terrain 45 | { 46 | sz hardwareConcurrency() 47 | { 48 | return std::thread::hardware_concurrency(); 49 | } 50 | 51 | #if defined(__APPLE__) 52 | size_t cache_line_size() 53 | { 54 | size_t line_size = 0; 55 | size_t sizeof_line_size = sizeof(line_size); 56 | sysctlbyname("hw.cachelinesize", &line_size, &sizeof_line_size, 0, 0); 57 | return line_size; 58 | } 59 | 60 | #elif defined(TERRAIN_WINDOWS) 61 | 62 | size_t cache_line_size() 63 | { 64 | size_t line_size = 0; 65 | DWORD buffer_size = 0; 66 | DWORD i = 0; 67 | SYSTEM_LOGICAL_PROCESSOR_INFORMATION* buffer = 0; 68 | 69 | GetLogicalProcessorInformation(0, &buffer_size); 70 | buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION*) emalloc(buffer_size); 71 | GetLogicalProcessorInformation(&buffer[0], &buffer_size); 72 | 73 | for(i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); 74 | ++i) 75 | { 76 | if(buffer[i].Relationship == RelationCache 77 | && buffer[i].Cache.Level == 1) 78 | { 79 | line_size = buffer[i].Cache.LineSize; 80 | break; 81 | } 82 | } 83 | 84 | free(buffer); 85 | return line_size; 86 | } 87 | 88 | #elif defined(TERRAIN_LINUX) 89 | 90 | size_t cache_line_size() 91 | { 92 | FILE* p = 0; 93 | p = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", 94 | "r"); 95 | unsigned int i = 0; 96 | if(p) 97 | { 98 | if(!fscanf(p, "%d", &i)) 99 | i = 64; 100 | fclose(p); 101 | } 102 | return i; 103 | } 104 | 105 | #else 106 | #error "Unrecognized platform" 107 | #endif 108 | 109 | //TODO: make bindToProcessor() work for more than 64 cores! 110 | 111 | #ifdef TERRAIN_WINDOWSGCCx64 112 | void bindToProcessor(sz n) 113 | { 114 | if(::SetThreadAffinityMask(::GetCurrentThread(), (DWORD_PTR)1 << n) == 0) 115 | throw std::runtime_error("::SetThreadAffinityMask() failed"); 116 | } 117 | 118 | #elif defined TERRAIN_LINUXGCCx64 119 | void bindToProcessor(sz n) 120 | { 121 | cpu_set_t cpuset; 122 | CPU_ZERO(&cpuset); 123 | CPU_SET(n, &cpuset); 124 | 125 | int errno_( 126 | ::pthread_setaffinity_np(::pthread_self(), sizeof(cpuset), 127 | &cpuset)); 128 | if(errno_ != 0) 129 | throw std::runtime_error("::pthread_setaffinity_np() failed"); 130 | } 131 | 132 | #elif defined TERRAIN_BSDGCCx64 133 | void bindToProcessor(sz n) 134 | { 135 | cpuset_t cpuset; 136 | CPU_ZERO(& cpuset); 137 | CPU_SET(n, & cpuset); 138 | 139 | if(::cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset), 140 | & cpuset) == -1) 141 | throw std::runtime_error("::cpuset_setaffinity() failed"); 142 | } 143 | 144 | #else 145 | #error "Unrecognized platform" 146 | #endif 147 | 148 | } /* namespace terrain */ 149 | -------------------------------------------------------------------------------- /src/util/thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: thread.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include "types.h" 19 | 20 | /** 21 | * This is where low-level thread control and information functions are defined 22 | */ 23 | 24 | namespace terrain 25 | { 26 | 27 | /** 28 | * @return the number of hardware threads on the current machine 29 | */ 30 | extern sz hardwareConcurrency(); 31 | 32 | /** 33 | * @return the cache line size (in bytes) of the processor, or 0 on failure 34 | */ 35 | size_t cache_line_size(); 36 | 37 | /** 38 | * Bind the current thread to the given hardware thread ("processor"). 39 | * Binding a thread to a particular processor ensures that it wont be swapped 40 | * off of that hardware unit during execution. By ensuring this, typically 41 | * task switching costs and rates are reduced as well as cache misses. 42 | * 43 | * If running a thread pool, the best performance is typically achieved by 44 | * evenly distributing and binding each thread across the hardware processors. 45 | */ 46 | extern void bindToProcessor(sz processorID); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/util/tls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: tls.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | /** 20 | * Supplies simple thread-local storage. Typically more efficient than 21 | * std::thread_local. 22 | * 23 | * Defines the preprocessor directive tls(type, name) which declares a 24 | * thread local variable with the given type and name. 25 | * 26 | * Only use this for small primitive types like pointers and integers. 27 | * The more TLS entries that have to be maintained, the slower TLS access 28 | * becomes, so try not to use too many of these! 29 | * 30 | * For GCC, this aliases to __thread type name. 31 | */ 32 | 33 | #ifdef TERRAIN_GCC 34 | #include "tlsGCC.h" 35 | #else 36 | #error "Platform not supported." 37 | #endif 38 | -------------------------------------------------------------------------------- /src/util/tlsGCC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: tlsGCC.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "platformSpecific.h" 18 | 19 | /** 20 | * GCC implementation / aliases for thread local storage 21 | */ 22 | 23 | #if (defined TERRAIN_GCC) 24 | 25 | #define tls(type,name) __thread type name 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/util/tlsWindowsGCCx64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: tlsWindowsGCCx64.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "platformSpecific.h" 18 | 19 | #ifdef TERRAIN_WINDOWSGCCx64 20 | 21 | /** 22 | * Windows-based Mingw-GCC implementation for thread local storage. 23 | * 24 | * Uses windows API calls TlsAlloc(), TlsFree(), and handles the rest 25 | * using assembler calls (which have tested to be considerably faster than 26 | * the Windows calls). 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | namespace terrain 33 | { 34 | namespace detail 35 | { 36 | template 37 | struct tls_s 38 | { 39 | private: 40 | DWORD const offset; 41 | 42 | // typedef struct _TEB 43 | // { 44 | // BYTE Reserved1[1952]; 45 | // PVOID Reserved2[412]; 46 | // PVOID TlsSlots[64]; 47 | // BYTE Reserved3[8]; 48 | // PVOID Reserved4[26]; 49 | // PVOID ReservedForOle; 50 | // PVOID Reserved5[4]; 51 | // PVOID TlsExpansionSlots; 52 | // } TEB, *PTEB; 53 | 54 | public: 55 | 56 | tls_s() : 57 | offset(TlsAlloc()) 58 | { 59 | } 60 | 61 | ~tls_s() 62 | { 63 | TlsFree(offset); 64 | } 65 | 66 | T operator=(T value) 67 | { 68 | set(value); 69 | return value; 70 | } 71 | 72 | operator T() const 73 | { 74 | return get(); 75 | } 76 | 77 | private: 78 | inline T get() const 79 | { 80 | //return (T)TlsGetValue(offset); 81 | // return (T)((_TEB*) __readgsqword(FIELD_OFFSET(NT_TIB,Self)))->TlsSlots[offset]; 82 | //return (T)TlsGetValue(offset); 83 | // printf("FIELD_OFFSET(_TEB,tlsSlots[0]) = %p\n", (void*)FIELD_OFFSET(_TEB,TlsSlots[0])); 84 | // return (T)((_TEB*) __readgsqword(FIELD_OFFSET(NT_TIB,Self)))->TlsSlots[offset]; 85 | T result; 86 | asm(".intel_syntax \n" 87 | "movq %0, %%gs:[0x1480+%1*8]\n" 88 | ".att_syntax\n" 89 | : "=r"(result) : "r"(offset)); 90 | return result; 91 | } 92 | 93 | inline void set(T value) 94 | { 95 | // TlsSetValue(offset, (LPVOID)value); 96 | // ((_TEB*) __readgsqword(FIELD_OFFSET(NT_TIB,Self)))->TlsSlots[offset] = (PVOID)value; 97 | asm(".intel_syntax \n" 98 | "movq %%gs:[0x1480+%1*8], %0\n" 99 | ".att_syntax\n" 100 | : : "r"(value), "r"(offset) : "memory"); 101 | } 102 | 103 | // //assignment 104 | // inline tls& operator=(const tls &r) 105 | // { 106 | // set(r.get()); 107 | // return *this; 108 | // } 109 | // 110 | // template 111 | // inline tls& operator=(const V &r) 112 | // { 113 | // set(&r); 114 | // return *this; 115 | // } 116 | // 117 | // inline tls& operator=(const T &r) 118 | // { 119 | // set(&r); 120 | // return *this; 121 | // } 122 | // 123 | //// inline T& operator*() const 124 | //// { 125 | //// return get(); 126 | //// } 127 | // 128 | // inline T* operator->() 129 | // { 130 | // return get(); 131 | // } 132 | }; 133 | } 134 | 135 | #define tls(type,name) ctools::detail::tls_s name 136 | 137 | } /* namespace terrain */ 138 | -------------------------------------------------------------------------------- /src/util/toStringStream.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: toStringStream.h 3 | * Copyright 2016, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | 19 | namespace terrain 20 | { 21 | 22 | template 23 | static inline std::stringstream toStringStream(Args... args) 24 | { 25 | std::stringstream s; 26 | (void)(int[]) 27 | { 28 | 0, ((void)(s << args), 0) ... 29 | }; 30 | return s; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/util/type_name.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: type_name.h 3 | * Copyright 2016, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "platformSpecific.h" 22 | #include "types.h" 23 | 24 | #ifdef TERRAIN_GCC 25 | #include 26 | #endif 27 | 28 | namespace terrain 29 | { 30 | 31 | /** 32 | * Debugging utility for getting a string that contains the type name of 33 | * a particular type. Useful for certain template-based debugging applications 34 | * where the classname is not easily accessible. 35 | */ 36 | template 37 | std::string type_name() 38 | { 39 | std::string tname = typeid(T).name(); 40 | 41 | #ifdef TERRAIN_GCC 42 | int status; 43 | char* demangled_name = abi::__cxa_demangle(tname.c_str(), NULL, NULL, &status); 44 | if(status == 0) 45 | { 46 | tname = demangled_name; 47 | std::free(demangled_name); 48 | } 49 | #endif 50 | 51 | return tname; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/util/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: types.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** 23 | * Defines the terrain primitive types. 24 | */ 25 | 26 | namespace terrain 27 | { 28 | /** 29 | * A signed byte 30 | */ 31 | using sbyte = std::int8_t; 32 | 33 | /** 34 | * An unsigned byte 35 | */ 36 | using byte = std::uint8_t; 37 | 38 | /** 39 | * A signed 2-byte, 16-bit integer a.k.a "a short" 40 | */ 41 | using sht = std::int16_t; 42 | 43 | /** 44 | * An unsigned 2-byte, 16-bit integer a.k.a "an unsigned short" 45 | */ 46 | using usht = std::uint16_t; 47 | 48 | /** 49 | * A signed 4-byte, 32-bit integer a.k.a "an int" 50 | */ 51 | using intt = std::int32_t; 52 | 53 | /** 54 | * An unsigned 4-byte, 32-bit integer a.k.a "an unsigned int" 55 | */ 56 | using uint = std::uint32_t; 57 | 58 | /** 59 | * A signed 8-byte, 64-bit integer a.k.a "a long" 60 | */ 61 | using lng = std::int64_t; 62 | 63 | /** 64 | * An unsigned 8-byte, 64-bit integer a.k.a "an unsigned long" 65 | */ 66 | using ulng = std::uint64_t; 67 | 68 | /** 69 | * An unsigned integer with the same size as a data pointer like void*. 70 | * On 64-bit gcc, targeting x64, this is the same as a ulng: a 71 | * 64-bit unsigned integer. 72 | * 73 | * size_t and sz should be used for counting things, especially things 74 | * like array indexes and numbers of bytes. They are also what you get 75 | * back when subtracting pointers. 76 | * 77 | * If you need to access the value in a pointer as an integer, this is 78 | * the type you should cast it to. 79 | */ 80 | using sz = std::size_t; 81 | 82 | /** 83 | * A native signed integer type which has the greatest capacity without 84 | * sacrificing arithmetic performance, a.k.a "a num". 85 | * 86 | * In x64 systems this is the same as a lng. 87 | */ 88 | using nm = std::int_fast64_t; 89 | 90 | /** 91 | * A native unsigned integer type which has the greatest capacity without 92 | * sacrificing arithmetic performance, a.k.a "an unsigned num". 93 | * 94 | * In x64 systems this is the same as a ulng. 95 | */ 96 | using un = std::uint_fast64_t; 97 | 98 | /** 99 | * Terrain's common string class. The fact that it is std::string is beyond the point. 100 | */ 101 | using string = std::string; 102 | 103 | } // namespace terrain 104 | -------------------------------------------------------------------------------- /src/util/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: util.h 3 | * Copyright 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | /** 18 | * Includes the most useful definitions and functions in the util dir. 19 | */ 20 | 21 | #include 22 | #include "defs.hpp" 23 | #include "directives.h" 24 | #include "type_name.h" 25 | #include "DebugPrintf.h" 26 | 27 | #define MAX(a,b) ((a) > (b) ? (a) : (b)) 28 | #define MIN(a,b) ((a) < (b) ? (a) : (b)) 29 | 30 | namespace terrain 31 | { 32 | 33 | template 34 | using rr = std::remove_reference_t; //deprecated 35 | 36 | } 37 | -------------------------------------------------------------------------------- /test/frc/FRC_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: FRC_test.cpp 3 | * Copyright 2014, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | using namespace boost; 30 | 31 | using namespace terrain; 32 | 33 | using namespace terrain::frc; 34 | 35 | template using s = AtomicPointer; 36 | template using p = PrivatePointer; 37 | 38 | class FRCTest 39 | { 40 | public: 41 | 42 | static constexpr sz numStrings = 32; 43 | static constexpr sz num = 100000; 44 | 45 | std::vector> myStrings; 46 | 47 | terrain::atm go; 48 | 49 | void writer(sz i) 50 | { 51 | printf("writer %i start\n", (int)i); 52 | FRCToken t; 53 | sz acc = 0; 54 | 55 | p last; 56 | last = myStrings[0]; 57 | 58 | for(sz n = num; n > 0; n--) 59 | { 60 | un r = FastRNG::next(100); 61 | un index = FastRNG::next(numStrings); 62 | if(r >= 50) 63 | { 64 | // last.emplace("the valid string"); 65 | ostringstream convert; 66 | convert << "set: " << i << " " << index << " = " << acc; 67 | //if(p.length() == 0) 68 | //printf("length %d \"%p\"\n", (int)p.length(), p.c_str()); 69 | //writeFence(); 70 | //last = newString; 71 | myStrings[index].make(convert.str()); 72 | } 73 | else 74 | { 75 | myStrings[index] = last; 76 | } 77 | 78 | acc++; 79 | } 80 | 81 | printf("writer %i done\n", (int)i); 82 | } 83 | 84 | void reader(sz index) 85 | { 86 | constexpr bool debug = false; 87 | FRCToken t; 88 | 89 | //h p(myStrings[(stride + 17) % numStrings]); 90 | 91 | //sz i = 0; 92 | while(go.load(oacq)) 93 | { 94 | sz i = FastRNG::next(numStrings); 95 | if(debug) printf("first reading %d\n", (int)i); 96 | p a(myStrings[i]); 97 | 98 | checkString(*a); 99 | 100 | auto j = (i + 3) % numStrings; 101 | if(debug) printf("second reading %d\n", (int)j); 102 | p b(myStrings[j]); 103 | checkString(*b); 104 | 105 | if(debug) printf("%p : %p\n", a->c_str(), b->c_str()); 106 | //i = (i + stride) % numStrings; 107 | } 108 | } 109 | 110 | void checkString(string& p) 111 | { 112 | constexpr bool debug = false; 113 | if(debug) printf("check %p:\n", &p); 114 | sz len = p.size(); 115 | if(len > 100) 116 | { 117 | printf("Length too long %d\n", (int)len); 118 | if(len < 200) 119 | printf("Length too long %d, \"%p\"\n", (int)len, p.c_str()); 120 | 121 | ASSERT_TRUE(false); 122 | } 123 | 124 | if(p.c_str()[len] != '\0') 125 | { 126 | printf("string not terminated: %d, '%c'\n", (int)len, 127 | p.c_str()[len]); 128 | // if (len < 1000) 129 | // printf("string not terminated: %d, '%c', \"%p\"\n", (int) len, 130 | // p.c_str()[len], p.c_str()); 131 | ASSERT_TRUE(false); 132 | } 133 | 134 | ASSERT_TRUE(len < 200); 135 | ASSERT_TRUE(p.c_str()[len] == '\0'); 136 | for(sz i = 0; i < len; i++) 137 | { 138 | if(p.c_str()[i] == '\0') 139 | { 140 | printf("string not terminated: %d, '%c'\n", (int)len, 141 | p.c_str()[len]); 142 | if(len < 1000) 143 | printf("string not terminated: %d, '%c', \"%p\"\n", 144 | (int)len, p.c_str()[len], p.c_str()); 145 | ASSERT_TRUE(false); 146 | } 147 | } 148 | 149 | if(debug) printf("check %p passed\n", &p); 150 | } 151 | 152 | void Test() 153 | { 154 | go = true; 155 | 156 | setbuf(stdout, NULL); 157 | 158 | std::vector > writers; 159 | std::vector > readers; 160 | 161 | //myStrings = new h[numStrings]; 162 | myStrings.reserve(numStrings); 163 | for(sz i = 0; i < numStrings; i++) 164 | { 165 | myStrings.emplace_back("init"); 166 | } 167 | 168 | sz numWriters = 1 + hardwareConcurrency() / 2; 169 | sz numReaders = 1 + hardwareConcurrency() / 2; 170 | 171 | for(sz i = 0; i < numWriters; ++i) 172 | { 173 | writers.emplace_back(new thread(&FRCTest::writer, this, i)); 174 | } 175 | 176 | for(sz i = 0; i < numReaders; ++i) 177 | { 178 | readers.emplace_back(new thread(&FRCTest::reader, this, i)); 179 | } 180 | 181 | std::this_thread::sleep_for(100ms); 182 | 183 | for(auto& thread : writers) 184 | { 185 | thread->join(); 186 | } 187 | 188 | go = false; 189 | 190 | for(auto& thread : readers) 191 | { 192 | thread->join(); 193 | } 194 | } 195 | }; 196 | 197 | TEST(frcFRC, test) 198 | { 199 | FRCToken t; 200 | FRCTest x; 201 | x.Test(); 202 | } 203 | -------------------------------------------------------------------------------- /test/precompiled.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: precompiled.h 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #if __cplusplus < 201103L 18 | #define __cplusplus 201103L 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | 36 | #include 37 | 38 | using auto_cpu_timer = boost::timer::auto_cpu_timer; 39 | 40 | // 41 | //extern cute::suite testSuiteStack; 42 | //extern int ___secretCount; 43 | // 44 | /* 45 | #define RunAsTest(function) \ 46 | extern void function(); \ 47 | static int __init_f_ ## function() \ 48 | { \ 49 | testSuiteStack.push_back(CUTE(function)); \ 50 | return ___secretCount++; \ 51 | }\ 52 | int __init_x_ ## function = __init_f_ ## function(); 53 | 54 | #define DefineTest(testName) \ 55 | static void testName ## _test(void);\ 56 | static int __init_f_ ## testName() \ 57 | { \ 58 | testSuiteStack.push_back(CUTE(testName ## _test)); \ 59 | return ___secretCount++;\ 60 | }\ 61 | int __init_x_ ## testName = __init_f_ ## testName(); \ 62 | static void testName ## _test (void) 63 | */ 64 | 65 | inline void dprintt(char const* message, ...) 66 | { 67 | sz const bufferLength = 1024; 68 | sz const maxLength = bufferLength - sizeof(char); 69 | char buffer[bufferLength]; 70 | 71 | va_list argptr; 72 | va_start(argptr, message); 73 | vsnprintf(buffer, maxLength, message, argptr); 74 | va_end(argptr); 75 | 76 | std::cout << buffer; 77 | } 78 | -------------------------------------------------------------------------------- /test/synchronization/MutexSpin_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: MutexSpin_tests.cpp 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include "MutexTestModule.h" 19 | 20 | namespace 21 | { 22 | 23 | using namespace MutexTests; 24 | using Module = MutexTestModule<::MutexSpin>; 25 | 26 | TEST(MutexSpin_tests, uncontended) 27 | { 28 | Module::test(1, 1); 29 | } 30 | 31 | TEST(MutexSpin_tests, 1x2) 32 | { 33 | Module::test(1, 2); 34 | } 35 | 36 | TEST(MutexSpin_tests, 1x4) 37 | { 38 | Module::test(1, 4); 39 | } 40 | 41 | TEST(MutexSpin_tests, 1x8) 42 | { 43 | Module::test(1, 8); 44 | } 45 | 46 | TEST(MutexSpin_tests, 1x16) 47 | { 48 | Module::test(1, 16); 49 | } 50 | 51 | TEST(MutexSpin_tests, 1x32) 52 | { 53 | Module::test(1, 32); 54 | } 55 | 56 | TEST(MutexSpin_tests, 1x64) 57 | { 58 | Module::test(1, 64); 59 | } 60 | 61 | TEST(MutexSpin_tests, 2x2) 62 | { 63 | Module::test(2, 2); 64 | } 65 | 66 | TEST(MutexSpin_tests, 8x2) 67 | { 68 | Module::test(8, 2); 69 | } 70 | 71 | TEST(MutexSpin_tests, 2x8) 72 | { 73 | Module::test(2, 8); 74 | } 75 | 76 | TEST(MutexSpin_tests, 16x16) 77 | { 78 | Module::test(16, 16); 79 | } 80 | 81 | TEST(MutexSpin_tests, 32x32) 82 | { 83 | Module::test(32, 32); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /test/synchronization/MutexTestModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: MutexTestModule.h 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #pragma once 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace MutexTests 25 | { 26 | using namespace terrain; 27 | 28 | template 29 | struct MutexTestModule 30 | { 31 | std::unique_ptr mut; 32 | sz count; 33 | 34 | static constexpr sz numCounts = 10; 35 | std::unique_ptr counts[numCounts]; 36 | 37 | MutexTestModule() : 38 | mut(new Mutex()), 39 | count(0) 40 | { 41 | for(sz i = 0; i < numCounts; ++i) 42 | counts[i].reset(new sz(0)); 43 | } 44 | 45 | void check() 46 | { 47 | for(sz i = 0; i < numCounts; ++i) 48 | { 49 | ASSERT_TRUE(count == *counts[i]) 50 | << "count: " << count 51 | << " counts[" << i << "]: " << *counts[i]; 52 | } 53 | } 54 | 55 | void adjust() 56 | { 57 | std::lock_guard l(*mut); 58 | check(); 59 | 60 | ++count; 61 | for(sz i = 0; i < numCounts; ++i) 62 | ++*counts[numCounts - i - 1]; 63 | 64 | check(); 65 | } 66 | 67 | static void testLoop(sz numIncrements, std::vector& modules) 68 | { 69 | while(numIncrements-- > 0) 70 | { 71 | sz index = FastRNG::next(modules.size()); 72 | auto& module = modules[index]; 73 | module.adjust(); 74 | } 75 | } 76 | 77 | 78 | #ifdef DEBUG 79 | static constexpr sz numIncrements = 100000; 80 | #else 81 | static constexpr sz numIncrements = 10000000; 82 | #endif 83 | 84 | static void testTask(sz i, sz numIncrements, std::vector& modules) 85 | { 86 | if(i == 0) 87 | { 88 | auto_cpu_timer t; 89 | testLoop(numIncrements, modules); 90 | } 91 | else 92 | { 93 | testLoop(numIncrements, modules); 94 | } 95 | } 96 | 97 | static void test(sz numMutexes, sz numThreads) 98 | { 99 | std::vector modules(numMutexes); 100 | std::vector threads; 101 | threads.reserve(numThreads); 102 | auto numIncrementsPerRequest = numIncrements / numThreads; 103 | 104 | { 105 | auto_cpu_timer t; 106 | for(sz i = 0; i < numThreads; ++i) 107 | { 108 | threads.emplace_back( 109 | [&, i, numIncrementsPerRequest]() 110 | { 111 | testTask(i, numIncrementsPerRequest, modules); 112 | }); 113 | } 114 | 115 | for(auto& t : threads) 116 | t.join(); 117 | } 118 | 119 | for(auto& m : modules) 120 | m.check(); 121 | } 122 | 123 | }; 124 | 125 | } 126 | -------------------------------------------------------------------------------- /test/synchronization/std_Mutex_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: std_Mutex_tests.cpp 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include "MutexTestModule.h" 19 | 20 | namespace 21 | { 22 | using namespace MutexTests; 23 | using Module = MutexTestModule; 24 | 25 | TEST(Mutex_std_tests, uncontended) 26 | { 27 | Module::test(1, 1); 28 | } 29 | 30 | TEST(Mutex_std_tests, 1x2) 31 | { 32 | Module::test(1, 2); 33 | } 34 | 35 | TEST(Mutex_std_tests, 1x4) 36 | { 37 | Module::test(1, 4); 38 | } 39 | 40 | TEST(Mutex_std_tests, 1x8) 41 | { 42 | Module::test(1, 8); 43 | } 44 | 45 | TEST(Mutex_std_tests, 1x16) 46 | { 47 | Module::test(1, 16); 48 | } 49 | 50 | TEST(Mutex_std_tests, 1x32) 51 | { 52 | Module::test(1, 32); 53 | } 54 | 55 | TEST(Mutex_std_tests, 1x64) 56 | { 57 | Module::test(1, 64); 58 | } 59 | 60 | TEST(Mutex_std_tests, 16x16) 61 | { 62 | Module::test(16, 16); 63 | } 64 | 65 | TEST(Mutex_std_tests, 16x32) 66 | { 67 | Module::test(16, 32); 68 | } 69 | 70 | TEST(Mutex_std_tests, 32x16) 71 | { 72 | Module::test(32, 16); 73 | } 74 | 75 | TEST(Mutex_std_tests, 32x32) 76 | { 77 | Module::test(32, 32); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /test/util/ExceptionTests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: ExceptionTests.cpp 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | TEST(Exception, test) 21 | { 22 | Exception x(string("Something bad")); 23 | 24 | std::cout << x.what() << std::endl; 25 | } 26 | -------------------------------------------------------------------------------- /test/util/bitTricks_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: bitTricks_tests.cpp 3 | * Copyright 2013, 2017 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | TEST(bitTricks, test) 22 | { 23 | // find popcount tests in popcount_t.cpp 24 | 25 | // floorLog2 & countLeadingZeros 26 | ASSERT_EQ(terrain::floorLog2(uint(0)), uint(0)); 27 | ASSERT_EQ(terrain::floorLog2(uint(1)), uint(0)); 28 | 29 | ASSERT_EQ(terrain::countLeadingZeros(uint(0)), uint(32)); 30 | ASSERT_EQ(terrain::countLeadingZeros(uint(1)), uint(31)); 31 | 32 | ASSERT_EQ(terrain::countLeadingZeros(ulng(0)), uint(64)); 33 | ASSERT_EQ(terrain::countLeadingZeros(ulng(1)), uint(63)); 34 | 35 | for(uint i = 1, k = 2; i != 32 ; ++i, k *= 2) 36 | { 37 | // std::cout << "k:"<(1)); 62 | ASSERT_TRUE(terrain::fits(0xFFFFFFF)); 63 | ASSERT_TRUE(!terrain::fits(0x100)); 64 | 65 | ASSERT_TRUE(terrain::fits(1, 0xFFFFFF)); 66 | 67 | ASSERT_TRUE(!terrain::fits(0x100, 0xFF)); 68 | 69 | // isPowerOfTwo 70 | ASSERT_TRUE(terrain::isPowerOfTwo(1)); 71 | ASSERT_TRUE(terrain::isPowerOfTwo(2)); 72 | ASSERT_TRUE(!terrain::isPowerOfTwo(3)); 73 | ASSERT_TRUE(terrain::isPowerOfTwo(4096)); 74 | ASSERT_TRUE(!terrain::isPowerOfTwo(4095)); 75 | ASSERT_TRUE(terrain::isPowerOfTwo(32768)); 76 | ASSERT_TRUE(!terrain::isPowerOfTwo(32769)); 77 | 78 | // countTrailingZeros 79 | 80 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 0), sz(64)); 81 | ASSERT_EQ(terrain::countTrailingZeros((uint) 0), sz(32)); 82 | ASSERT_EQ(terrain::countTrailingZeros((usht) 0), sz(16)); 83 | ASSERT_EQ(terrain::countTrailingZeros((byte) 0), sz(8)); 84 | 85 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 1), sz(0)); 86 | ASSERT_EQ(terrain::countTrailingZeros((byte) 1), 0); 87 | ASSERT_EQ(terrain::countTrailingZeros((usht) 1), 0); 88 | ASSERT_EQ(terrain::countTrailingZeros((uint) 1), 0); 89 | 90 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 2), 1); 91 | ASSERT_EQ(terrain::countTrailingZeros((uint) 2), 1); 92 | 93 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 3), 0); 94 | ASSERT_EQ(terrain::countTrailingZeros((uint) 3), 0); 95 | 96 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 4), 2); 97 | ASSERT_EQ(terrain::countTrailingZeros((uint) 4), 2); 98 | 99 | ASSERT_EQ(terrain::countTrailingZeros((ulng) 9), 0); 100 | 101 | ASSERT_EQ(terrain::countTrailingZeros((uint) 0x100), 8); 102 | ASSERT_EQ(terrain::countTrailingZeros((uint) 0x102), 1); 103 | 104 | // rotl 105 | ASSERT_EQ(terrain::rotl((uint) 1, 0), sz(1)); 106 | ASSERT_EQ(terrain::rotl((uint) 1, 1), sz(2)); 107 | ASSERT_EQ(terrain::rotl((uint) 1, 2), sz(4)); 108 | ASSERT_EQ(terrain::rotl((uint) 1, 4), sz(16)); 109 | ASSERT_EQ(terrain::rotl((uint) 1, 8), sz(256)); 110 | ASSERT_EQ(terrain::rotl((uint) 1, 32), sz(1)); 111 | ASSERT_EQ(terrain::rotl((uint) 2, 31), sz(1)); 112 | ASSERT_EQ(terrain::rotl((uint) 6, 31), sz(3)); 113 | ASSERT_EQ(terrain::rotl((uint) 0, 4), sz(0)); 114 | 115 | } 116 | 117 | -------------------------------------------------------------------------------- /test/util/thread_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: thread_tests.cpp 3 | * Copyright 2016-7 Terrain Data, Inc. 4 | * 5 | * This file is part of FRC, a fast reference counting library for C++ 6 | * (see ). 7 | * 8 | * FRC is distributed under the MIT License, which is found in 9 | * COPYING.md in the repository. 10 | * 11 | * You should have received a copy of the MIT License 12 | * along with FRC. If not, see . 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | TEST(thread, test) 21 | { 22 | ASSERT_EQ(terrain::cache_line_size(), sz(64)); 23 | } 24 | --------------------------------------------------------------------------------