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