📄 memory_algorithm_test_template.hpp
字号:
////////////////////////////////////////////////////////////////////////////////// (C) Copyright Ion Gaztanaga 2006. Distributed under the Boost// Software License, Version 1.0. (See accompanying file// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// See http://www.boost.org/libs/interprocess for documentation.////////////////////////////////////////////////////////////////////////////////#ifndef BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER#define BOOST_INTERPROCESS_TEST_MEMORY_ALGORITHM_TEST_TEMPLATE_HEADER#include <boost/interprocess/detail/config_begin.hpp>#include <vector>#include <iostream>#include <new>#include <utility>#include <cstring> //std::memset#include <cstdio> //std::removenamespace boost { namespace interprocess { namespace test {enum deallocation_type { DirectDeallocation, InverseDeallocation, MixedDeallocation, EndDeallocationType };//This test allocates until there is no more memory//and after that deallocates all in the inverse ordertemplate<class Allocator>bool test_allocation(Allocator &a){ for( deallocation_type t = DirectDeallocation ; t != EndDeallocationType ; t = (deallocation_type)((int)t + 1)){ std::vector<void*> buffers; std::size_t free_memory = a.get_free_memory(); for(int i = 0; true; ++i){ void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } switch(t){ case DirectDeallocation: { for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ a.deallocate(buffers[j]); } } break; case InverseDeallocation: { for(int j = (int)buffers.size() ;j-- ;){ a.deallocate(buffers[j]); } } break; case MixedDeallocation: { for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; a.deallocate(buffers[pos]); buffers.erase(buffers.begin()+pos); } } break; default: break; } bool ok = free_memory == a.get_free_memory() && a.all_memory_deallocated() && a.check_sanity(); if(!ok) return ok; } return true;}//This test allocates until there is no more memory//and after that tries to shrink all the buffers to the//half of the original sizetemplate<class Allocator>bool test_allocation_shrink(Allocator &a){ std::vector<void*> buffers; //Allocate buffers with extra memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i*2, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } //Now shrink to half for(int i = 0, max = (int)buffers.size() ;i < max ; ++i){ std::size_t received_size; if(a.template allocation_command<char> ( shrink_in_place | nothrow_allocation, i*2 , i, received_size, static_cast<char*>(buffers[i])).first){ if(received_size > std::size_t(i*2)){ return false; } if(received_size < std::size_t(i)){ return false; } std::memset(buffers[i], 0, a.size(buffers[i])); } } //Deallocate it in non sequential order for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; a.deallocate(buffers[pos]); buffers.erase(buffers.begin()+pos); } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates until there is no more memory//and after that tries to expand all the buffers to//avoid the wasted internal fragmentationtemplate<class Allocator>bool test_allocation_expand(Allocator &a){ std::vector<void*> buffers; //Allocate buffers with extra memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } //Now try to expand to the double of the size for(int i = 0, max = (int)buffers.size() ;i < max ;++i){ std::size_t received_size; std::size_t min_size = i+1; std::size_t preferred_size = i*2; preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command<char> ( expand_fwd | nothrow_allocation, min_size , preferred_size, received_size, static_cast<char*>(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ return false; } //Now, try to expand further min_size = received_size+1; preferred_size = min_size*2; } } //Deallocate it in non sequential order for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; a.deallocate(buffers[pos]); buffers.erase(buffers.begin()+pos); } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates until there is no more memory//and after that tries to expand all the buffers to//avoid the wasted internal fragmentationtemplate<class Allocator>bool test_allocation_shrink_and_expand(Allocator &a){ std::vector<void*> buffers; std::vector<std::size_t> received_sizes; std::vector<bool> size_reduced; //Allocate buffers wand store received sizes for(int i = 0; true; ++i){ std::size_t received_size; void *ptr = a.template allocation_command<char> ( allocate_new | nothrow_allocation, i, i*2, received_size).first; if(!ptr){ ptr = a.template allocation_command<char> ( allocate_new | nothrow_allocation, 1, i*2, received_size).first; if(!ptr) break; } buffers.push_back(ptr); received_sizes.push_back(received_size); } //Now shrink to half for(int i = 0, max = (int)buffers.size() ; i < max ; ++i){ std::size_t received_size; if(a.template allocation_command<char> ( shrink_in_place | nothrow_allocation, received_sizes[i] , i, received_size, static_cast<char*>(buffers[i])).first){ if(received_size > std::size_t(received_sizes[i])){ return false; } if(received_size < std::size_t(i)){ return false; } size_reduced.push_back(received_size != received_sizes[i]); } } //Now try to expand to the original size for(int i = 0, max = (int)buffers.size() ;i < max ;++i){ std::size_t received_size; std::size_t request_size = received_sizes[i]; if(a.template allocation_command<char> ( expand_fwd | nothrow_allocation, request_size , request_size, received_size, static_cast<char*>(buffers[i])).first){ if(received_size != received_sizes[i]){ return false; } } else{ return false; } } //Deallocate it in non sequential order for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; a.deallocate(buffers[pos]); buffers.erase(buffers.begin()+pos); } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates until there is no more memory//and after that deallocates the odd buffers to//make room for expansions. The expansion will probably//success since the deallocation left room for that.template<class Allocator>bool test_allocation_deallocation_expand(Allocator &a){ std::vector<void*> buffers; //Allocate buffers with extra memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } //Now deallocate the half of the blocks //so expand maybe can merge new free blocks for(int i = 0, max = (int)buffers.size() ;i < max ;++i){ if(i%2){ a.deallocate(buffers[i]); buffers[i] = 0; } } //Now try to expand to the double of the size for(int i = 0, max = (int)buffers.size() ;i < max ;++i){ // if(buffers[i]){ std::size_t received_size; std::size_t min_size = i+1; std::size_t preferred_size = i*2; preferred_size = min_size > preferred_size ? min_size : preferred_size; while(a.template allocation_command<char> ( expand_fwd | nothrow_allocation, min_size , preferred_size, received_size, static_cast<char*>(buffers[i])).first){ //Check received size is bigger than minimum if(received_size < min_size){ return false; } //Now, try to expand further min_size = received_size+1; preferred_size = min_size*2; } } } //Now erase null values from the vector buffers.erase( std::remove(buffers.begin(), buffers.end(), static_cast<void*>(0)) , buffers.end()); //Deallocate it in non sequential order for(int j = 0, max = (int)buffers.size() ;j < max ;++j){ int pos = (j%4)*((int)buffers.size())/4; a.deallocate(buffers[pos]); buffers.erase(buffers.begin()+pos); } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates until there is no more memory//and after that deallocates all except the last.//If the allocation algorithm is a bottom-up algorithm//the last buffer will be in the end of the segment.//Then the test will start expanding backwards, until//the buffer fills all the memorytemplate<class Allocator>bool test_allocation_with_reuse(Allocator &a){ //We will repeat this test for different sized elements for(int sizeof_object = 1; sizeof_object < 20; ++sizeof_object){ std::vector<void*> buffers; //Allocate buffers with extra memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i*sizeof_object, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 0, size); buffers.push_back(ptr); } //Now deallocate all except the latest //Now try to expand to the double of the sizeof_object for(int i = 0, max = (int)buffers.size() - 1 ;i < max ;++i){ a.deallocate(buffers[i]); } //Save the unique buffer and clear vector void *ptr = buffers.back(); buffers.clear(); //Now allocate with reuse std::size_t received_size = 0; for(int i = 0; true; ++i){ std::size_t min_size = (received_size + 1); std::size_t prf_size = (received_size + (i+1)*2); std::pair<void*, bool> ret = a.raw_allocation_command ( expand_bwd | nothrow_allocation, min_size , prf_size, received_size, static_cast<char*>(ptr), sizeof_object); if(!ret.first) break; //If we have memory, this must be a buffer reuse if(!ret.second) return 1; if(received_size < min_size) return 1; ptr = ret.first; } //There is only a single block so deallocate it a.deallocate(ptr); if(!a.all_memory_deallocated() || !a.check_sanity()) return false; } return true;}//This test allocates memory with different alignments//and checks returned memory is aligned.template<class Allocator>bool test_aligned_allocation(Allocator &a){ //Allocate aligned buffers in a loop //and then deallocate it bool continue_loop = true; for(unsigned int i = 1; continue_loop; i <<= 1){ for(unsigned int j = 1; true; j <<= 1){ void *ptr = a.allocate_aligned(i-1, j, std::nothrow); if(!ptr){ if(j == 1) continue_loop = false; break; } if(((std::size_t)ptr & (j - 1)) != 0) return false; a.deallocate(ptr); if(!a.all_memory_deallocated() || !a.check_sanity()){ return false; } } } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates memory with different alignments//and checks returned memory is aligned.template<class Allocator>bool test_continuous_aligned_allocation(Allocator &a){ std::vector<void*> buffers; //Allocate aligned buffers in a loop //and then deallocate it bool continue_loop = true; for(unsigned i = 1; continue_loop && i; i <<= 1){ for(unsigned int j = 1; j; j <<= 1){ for(bool any_allocated = false; 1;){ void *ptr = a.allocate_aligned(i-1, j, std::nothrow); buffers.push_back(ptr); if(!ptr){ if(j == 1 && !any_allocated){ continue_loop = false; } break; } else{ any_allocated = true; } if(((std::size_t)ptr & (j - 1)) != 0) return false; } //Deallocate all for(unsigned int k = (int)buffers.size(); k--;){ a.deallocate(buffers[k]); } buffers.clear(); if(!a.all_memory_deallocated() && a.check_sanity()) return false; if(!continue_loop) break; } } return a.all_memory_deallocated() && a.check_sanity();}//This test allocates memory, writes it with a non-zero value and//tests zero_free_memory initializes to zero for the next allocationtemplate<class Allocator>bool test_clear_free_memory(Allocator &a){ std::vector<void*> buffers; //Allocate memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; std::size_t size = a.size(ptr); std::memset(ptr, 1, size); buffers.push_back(ptr); } //Mark it for(int i = 0, max = buffers.size(); i < max; ++i){ std::memset(buffers[i], 1, i); } //Deallocate all for(int j = (int)buffers.size() ;j-- ;){ a.deallocate(buffers[j]); } buffers.clear(); if(!a.all_memory_deallocated() && a.check_sanity()) return false; //Now clear all free memory a.zero_free_memory(); if(!a.all_memory_deallocated() && a.check_sanity()) return false; //Now test all allocated memory is zero //Allocate memory for(int i = 0; true; ++i){ void *ptr = a.allocate(i, std::nothrow); if(!ptr) break; buffers.push_back(ptr); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -