1 #ifdef COMPILATION_INSTRUCTIONS
2 (echo "#include\""$0"\"" > $0.cpp) && c++ -std=c++17 -Wall -Wextra -Wfatal-errors -D_TEST_BOOST_MULTI_MEMORY_INSTRUMENTED $0.cpp -o $0x && valgrind $0x && rm $0x $0.cpp; exit
3 #endif
4 #ifndef BOOST_MULTI_MEMORY_INSTRUMENTED_HPP
5 #define BOOST_MULTI_MEMORY_INSTRUMENTED_HPP
6 
7 #include<cstddef> // max_align_t
8 #include<memory>
9 #include<stack>
10 #include<cassert>
11 #include<stdexcept>
12 #include<map>
13 
14 #include<memory_resource>
15 
16 //#include "../memory/block.hpp"
17 //#include "../memory/allocator.hpp"
18 
19 #include<numeric> // accumulate
20 #include<iostream>
21 namespace boost{
22 namespace multi{
23 namespace memory{
24 
25 template<
26 	class MemoryResource = std::pmr::memory_resource,
27 	typename SizeType = std::size_t,
28 	typename VoidPointer = void*
29 >
30 class instrumented{
31 	MemoryResource* back_ = std::pmr::get_default_resource();
32 	using void_pointer = VoidPointer;
33 	using size_type = SizeType;
34 	std::map<void_pointer, std::ptrdiff_t> blocks_;
35 public:
36 	instrumented() = default;
37 	instrumented(instrumented const&) = delete;
blocks() const38 	std::map<void_pointer, std::ptrdiff_t> const& blocks() const{return blocks_;}
leak()39 	auto leak(){
40 		return std::accumulate(
41 			blocks_.begin(), blocks_.end(), size_type{}, [](auto a, auto&& e){return a+e.second;}
42 		);
43 	}
44 	typename instrumented::void_pointer
allocate(size_type required_bytes,size_type align=alignof (std::max_align_t))45 	allocate(size_type required_bytes, size_type align = alignof(std::max_align_t)){
46 		std::cout << "allocating " << required_bytes << std::endl;
47 		auto ret = back_->allocate(required_bytes, align);
48 		blocks_[ret] += required_bytes;
49 		return ret;
50 	}
deallocate(typename instrumented::void_pointer p,typename instrumented::size_type discarded_bytes,size_type align=alignof (std::max_align_t))51 	void deallocate(typename instrumented::void_pointer p, typename instrumented::size_type discarded_bytes, size_type align = alignof(std::max_align_t)){
52 		std::cout << "deallocating " << discarded_bytes << std::endl;
53 		back_->deallocate(p, discarded_bytes, align);
54 		blocks_[p] -= discarded_bytes;
55 	}
56 };
57 }}}
58 
59 #include "../../multi/memory/allocator.hpp"
60 
61 namespace boost{
62 namespace multi{
63 namespace memory{
64 
65 template<class T>
66 using instrumented_allocator = multi::memory::allocator<T, multi::memory::instrumented<>>;
67 
68 }}}
69 
70 #if _TEST_BOOST_MULTI_MEMORY_INSTRUMENTED
71 
72 #include "../../multi/array.hpp"
73 #include "../memory/monotonic.hpp"
74 
75 #include<iostream>
76 #include<vector>
77 #include<cmath>
78 
79 namespace multi = boost::multi;
80 using std::cout;
81 
main()82 int main(){
83 {
84 	multi::memory::instrumented<> im;
85 	auto p1 = im.allocate(1*sizeof(double), alignof(double));
86 	auto p2 = im.allocate(255*sizeof(double), alignof(double));
87 	im.deallocate(p2, 255*sizeof(double));
88 	im.deallocate(p1, 1*sizeof(double));
89 	assert( im.blocks().size() == 2 );
90 	assert( not im.leak() );
91 	{
92 		multi::memory::instrumented<> im;
93 		multi::memory::allocator<double, multi::memory::instrumented<> > A(&im);
94 		double* p = A.allocate(1);
95 		A.construct(p, 8.);
96 		assert( *p == 8. );
97 		double* arr = A.allocate(255);
98 		A.construct(arr, 81.);
99 		assert( *arr == 81. );
100 		A.deallocate(arr, 255);
101 		A.deallocate(p, 1);
102 		assert( not im.leak() );
103 	}
104 	{
105 		multi::memory::instrumented<> im;
106 		multi::memory::allocator<double, multi::memory::instrumented<> > A(&im);
107 		{
108 			std::vector<double, decltype(A)> v(A);
109 			v.push_back(99);
110 			v.push_back(10);
111 			v.push_back(12);
112 			v.resize(1);
113 			v.push_back(10);
114 		}
115 		assert( not im.leak() );
116 	}
117 	{
118 		multi::memory::instrumented<> im;
119 		using alloc = multi::memory::instrumented_allocator<double>;
120 		alloc A(&im);
121 		alloc B(A);
122 		{
123 			multi::static_array<double, 1, alloc> arr1({10}, 99., A);
124 			multi::static_array<double, 2, alloc> arr2({10, 20}, 99., A);
125 			multi::static_array<double, 3, alloc> arr3({10, 20, 30}, 99., B);
126 			multi::static_array<double, 3, alloc> brr3(arr3);
127 		}
128 		assert( not im.leak() );
129 	}
130 	{
131 		multi::memory::instrumented<> im;
132 		multi::memory::allocator<double, multi::memory::instrumented<> > A(&im);
133 		{
134 			multi::array<double, 1, decltype(A)> arr1({10}, 99., A);
135 			multi::array<double, 2, decltype(A)> arr2({10, 20}, 99., A);
136 			multi::array<double, 3, decltype(A)> arr3({10, 20, 30}, 99., A);
137 		}
138 		assert( not im.leak() );
139 	}
140 	{
141 		multi::memory::instrumented<> im;
142 		{
143 			using alloc = multi::memory::instrumented_allocator<double>;
144 			multi::array<double, 3, alloc> A({10, 20, 30}, 99., &im);
145 			multi::array<double, 3, alloc> B({10, 20, 30}, 11., &im);
146 			B = std::move(A); assert( empty(A) );
147 		}
148 		assert( not im.leak() );
149 	}
150 	std::cout << "-------------------" << std::endl;
151 	{
152 		multi::memory::instrumented<> im;
153 		{
154 			using alloc = multi::memory::instrumented_allocator<double>;
155 		//	using alloc = std::allocator<double>;
156 			multi::array<double, 1, alloc> arr1({10}, 99., &im);
157 			multi::array<double, 2, alloc> arr2({10, 20}, 99., &im);
158 			multi::array<double, 3, alloc> arr3({10, 20, 30}, 99., &im);
159 			arr1.reextent({20});
160 			arr2.reextent({200, 10});
161 			arr3.reextent({201, 10, 100});
162 			arr2.clear();
163 			multi::array<double, 1, alloc> brr1 = arr1;
164 			multi::array<double, 2, alloc> brr2(arr2);
165 			assert( arr3.num_elements() == 201*10*100 );
166 			multi::array<double, 3, alloc> brr3(std::move(arr3));
167 			assert( arr3.num_elements() == 0 );
168 			assert( brr3.num_elements() == 201*10*100 );
169 		}
170 		assert( not im.leak() );
171 	}
172 	return 0;
173 //	return 0;
174 }
175 }
176 #endif
177 #endif
178 
179