├── README.md ├── include └── variti │ ├── slab.hpp │ └── util │ ├── thread_local_slab.hpp │ ├── slab.hpp │ ├── slab_ptr.hpp │ └── slab_allocator.hpp ├── CMakeLists.txt ├── example ├── slab_example1.cpp ├── slab_example2.cpp ├── slab_example3.cpp └── CMakeLists.txt └── src └── util ├── thread_local_slab.cpp └── slab.cpp /README.md: -------------------------------------------------------------------------------- 1 | # slab-allocator -------------------------------------------------------------------------------- /include/variti/slab.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | -------------------------------------------------------------------------------- /include/variti/util/thread_local_slab.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace variti { namespace util { 6 | 7 | class thread_local_slab 8 | { 9 | public: 10 | 11 | static void initialize(std::size_t size, std::size_t min_object_size, float factor); 12 | static void finalize(); 13 | 14 | static slab& inst(); 15 | }; 16 | 17 | }} 18 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(variti-slab) 4 | 5 | set(CMAKE_CXX_FLAGS "-std=c++11") 6 | set(CMAKE_CXX_FLAGS_RELEASE "-g -O3") 7 | set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") 8 | 9 | include_directories(/usr/include) 10 | include_directories(/usr/include/small/third_party) 11 | include_directories(include) 12 | 13 | add_library( 14 | variti-slab 15 | src/util/slab.cpp 16 | src/util/thread_local_slab.cpp) 17 | -------------------------------------------------------------------------------- /example/slab_example1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | using namespace variti; 9 | using namespace variti::util; 10 | thread_local_slab::initialize(1024 * 1024 * 1024, 2, 2.f); 11 | slab_allocator allocator; 12 | std::list> list(allocator); 13 | list.push_back(1); 14 | list.push_back(2); 15 | list.push_back(3); 16 | for (auto& item : list) 17 | std::cout << item << "\n"; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/util/thread_local_slab.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace variti { namespace util { 4 | 5 | thread_local slab* slab_ = nullptr; 6 | 7 | void thread_local_slab::initialize(std::size_t size, std::size_t min_object_size, float factor) 8 | { 9 | assert(!slab_); 10 | slab_ = new slab(size, min_object_size, factor); 11 | } 12 | 13 | void thread_local_slab::finalize() 14 | { 15 | assert(slab_); 16 | delete slab_; 17 | slab_ = nullptr; 18 | } 19 | 20 | slab& thread_local_slab::inst() 21 | { 22 | assert(slab_); 23 | return *slab_; 24 | } 25 | 26 | }} 27 | -------------------------------------------------------------------------------- /example/slab_example2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) 7 | { 8 | using namespace variti; 9 | using namespace variti::util; 10 | thread_local_slab::initialize(1024 * 1024 * 1024, 2, 2.f); 11 | slab_allocator allocator; 12 | using int_ptr = std::shared_ptr; 13 | std::list> list(allocator); 14 | list.push_back(slab_allocate_shared(allocator, 1)); 15 | list.push_back(slab_allocate_shared(allocator, 2)); 16 | list.push_back(slab_allocate_shared(allocator, 3)); 17 | for (auto& item : list) { 18 | std::cout << *item << "\n"; 19 | item = nullptr; 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /example/slab_example3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | using namespace variti; 12 | using namespace variti::util; 13 | using boost::asio::io_context; 14 | thread_local_slab::initialize(1024 * 1024 * 1024, 2, 2.f); 15 | io_context io; 16 | slab_allocator allocator; 17 | using int_ptr = std::shared_ptr; 18 | std::list> list(allocator); 19 | list.push_back(slab_allocate_shared(allocator, &io, 1)); 20 | list.push_back(slab_allocate_shared(allocator, &io, 2)); 21 | list.push_back(slab_allocate_shared(allocator, &io, 3)); 22 | std::thread work( 23 | [&list]() { 24 | for (auto& item : list) { 25 | std::cout << *item << "\n"; 26 | item = nullptr; 27 | } 28 | }); 29 | io.run(); 30 | work.join(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(variti-slab-examples) 4 | 5 | set(CMAKE_CXX_FLAGS "-std=c++11") 6 | set(CMAKE_CXX_FLAGS_RELEASE "-g -O3") 7 | set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") 8 | 9 | include_directories(/usr/include) 10 | include_directories(/usr/include/small/third_party) 11 | include_directories(../include) 12 | 13 | add_executable( 14 | slab-example1 15 | ../src/util/slab.cpp 16 | ../src/util/thread_local_slab.cpp 17 | slab_example1.cpp) 18 | target_link_libraries( 19 | slab-example1 20 | small 21 | pthread) 22 | 23 | add_executable( 24 | slab-example2 25 | ../src/util/slab.cpp 26 | ../src/util/thread_local_slab.cpp 27 | slab_example2.cpp) 28 | target_link_libraries( 29 | slab-example2 30 | small 31 | pthread) 32 | 33 | add_executable( 34 | slab-example3 35 | ../src/util/slab.cpp 36 | ../src/util/thread_local_slab.cpp 37 | slab_example3.cpp) 38 | target_link_libraries( 39 | slab-example3 40 | small 41 | pthread) 42 | -------------------------------------------------------------------------------- /include/variti/util/slab.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace variti { namespace util { 11 | 12 | std::thread::id slab_get_thread_id(const void* p); 13 | 14 | class slab 15 | { 16 | public: 17 | 18 | slab(std::size_t size, std::size_t min_object_size, float factor); 19 | 20 | slab(const slab&) = delete; 21 | slab& operator=(const slab&) = delete; 22 | slab(slab&&) = delete; 23 | slab& operator=(slab&&) = delete; 24 | 25 | ~slab(); 26 | 27 | std::size_t size() const; 28 | std::size_t min_object_size() const; 29 | std::size_t max_object_size() const; 30 | float factor() const; 31 | 32 | void* malloc(std::size_t n); 33 | void free(const void* p, std::size_t n); 34 | 35 | private: 36 | 37 | std::size_t size_; 38 | std::size_t min_object_size_; 39 | float factor_; 40 | 41 | struct quota quota_; 42 | struct slab_arena arena_; 43 | struct slab_cache cache_; 44 | struct small_alloc allocator_; 45 | }; 46 | 47 | }} 48 | -------------------------------------------------------------------------------- /include/variti/util/slab_ptr.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace variti { namespace util { 8 | 9 | template 10 | std::shared_ptr slab_allocate_shared(Allocator allocator, Args... args) 11 | { 12 | T* p = allocator.allocate(1); 13 | new ((void*)p) T(std::forward(args)...); 14 | std::shared_ptr res(p, 15 | [allocator](T* p) mutable { 16 | p->~T(); 17 | allocator.deallocate(p, 1); 18 | }); 19 | return res; 20 | }; 21 | 22 | template 23 | std::shared_ptr slab_allocate_shared(Allocator allocator, boost::asio::io_context* io, Args... args) 24 | { 25 | T* p = allocator.allocate(1); 26 | new ((void*)p) T(std::forward(args)...); 27 | std::shared_ptr res(p, 28 | [allocator, io](T* p) mutable { 29 | io->post( 30 | [allocator, p]() mutable { 31 | p->~T(); 32 | allocator.deallocate(p, 1); 33 | }); 34 | }); 35 | return res; 36 | }; 37 | 38 | }} 39 | -------------------------------------------------------------------------------- /include/variti/util/slab_allocator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace variti { namespace util { 6 | 7 | template 8 | class slab_allocator 9 | { 10 | public: 11 | 12 | using value_type = T; 13 | using pointer = value_type*; 14 | using const_pointer = const value_type*; 15 | using reference = value_type&; 16 | using const_reference = const value_type&; 17 | 18 | template 19 | struct rebind 20 | { 21 | typedef slab_allocator other; 22 | }; 23 | 24 | slab_allocator() {} 25 | 26 | template 27 | slab_allocator(const slab_allocator &) {} 28 | 29 | pointer allocate(size_t n, const void* = 0) 30 | { 31 | auto p = static_cast(thread_local_slab::inst().malloc(sizeof(value_type) * n)); 32 | if (!p && n) 33 | throw std::bad_alloc(); 34 | return p; 35 | } 36 | 37 | void deallocate(const_pointer p, size_t n) 38 | { 39 | thread_local_slab::inst().free(p, sizeof(value_type) * n); 40 | } 41 | }; 42 | 43 | template <> 44 | class slab_allocator 45 | { 46 | public: 47 | 48 | using value_type = void; 49 | using pointer = void*; 50 | using const_pointer = const void*; 51 | 52 | template struct rebind { typedef slab_allocator other; }; 53 | }; 54 | 55 | }} 56 | -------------------------------------------------------------------------------- /src/util/slab.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace variti { namespace util { 4 | 5 | inline void* phys_to_virt_p(void* p) { return reinterpret_cast(p) + sizeof(std::thread::id); } 6 | inline size_t phys_to_virt_n(size_t n) { return n - sizeof(std::thread::id); } 7 | inline void* virt_to_phys_p(void* p) { return reinterpret_cast(p) - sizeof(std::thread::id); } 8 | inline size_t virt_to_phys_n(size_t n) { return n + sizeof(std::thread::id); } 9 | 10 | inline std::thread::id& phys_thread_id(void* p) 11 | { return *reinterpret_cast(p); } 12 | 13 | std::thread::id slab_get_thread_id(const void* p) 14 | { 15 | return phys_thread_id(virt_to_phys_p(const_cast(p))); 16 | } 17 | 18 | slab::slab(std::size_t size, std::size_t min_object_size, float factor) 19 | : size_(size) 20 | , min_object_size_(min_object_size) 21 | , factor_(factor) 22 | { 23 | quota_init("a_, QUOTA_MAX); 24 | slab_arena_create(&arena_, "a_, 0, size, MAP_PRIVATE); 25 | slab_cache_create(&cache_, &arena_); 26 | small_alloc_create(&allocator_, &cache_, min_object_size, factor); 27 | small_alloc_setopt(&allocator_, SMALL_DELAYED_FREE_MODE, true); 28 | allocator_.objsize_max; 29 | } 30 | 31 | slab::~slab() 32 | { 33 | small_alloc_destroy(&allocator_); 34 | slab_cache_destroy(&cache_); 35 | slab_arena_destroy(&arena_); 36 | } 37 | 38 | std::size_t slab::size() const 39 | { 40 | return size_; 41 | } 42 | 43 | std::size_t slab::min_object_size() const 44 | { 45 | return min_object_size_; 46 | } 47 | 48 | std::size_t slab::max_object_size() const 49 | { 50 | return allocator_.objsize_max; 51 | } 52 | 53 | float slab::factor() const 54 | { 55 | return factor_; 56 | } 57 | 58 | void* slab::malloc(size_t n) 59 | { 60 | auto phys_n = virt_to_phys_n(n); 61 | auto phys_p = smalloc(&allocator_, phys_n); 62 | if (!phys_p) 63 | return nullptr; 64 | phys_thread_id(phys_p) = std::this_thread::get_id(); 65 | return phys_to_virt_p(phys_p); 66 | } 67 | 68 | void slab::free(const void* p, size_t n) 69 | { 70 | auto phys_p = virt_to_phys_p(const_cast(p)); 71 | auto phys_n = virt_to_phys_n(n); 72 | assert(phys_thread_id(phys_p) == std::this_thread::get_id()); 73 | smfree(&allocator_, phys_p, phys_n); 74 | } 75 | 76 | }} 77 | --------------------------------------------------------------------------------