Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Allocator.cpp
Go to the documentation of this file.
1// @HEADER
2// ***********************************************************************
3//
4// Teuchos: Common Tools Package
5// Copyright (2004) Sandia Corporation
6//
7// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8// license for use of this work by or on behalf of the U.S. Government.
9//
10// Redistribution and use in source and binary forms, with or without
11// modification, are permitted provided that the following conditions are
12// met:
13//
14// 1. Redistributions of source code must retain the above copyright
15// notice, this list of conditions and the following disclaimer.
16//
17// 2. Redistributions in binary form must reproduce the above copyright
18// notice, this list of conditions and the following disclaimer in the
19// documentation and/or other materials provided with the distribution.
20//
21// 3. Neither the name of the Corporation nor the names of the
22// contributors may be used to endorse or promote products derived from
23// this software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36//
37// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38//
39// ***********************************************************************
40// @HEADER
41
45#include <string>
46#include <vector>
47
48namespace { // (anonymous)
49
50
51TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( Allocator, Test1, T )
52{
55 using std::endl;
56
57 Teuchos::OSTab tab0 (out);
58 out << "Test Teuchos::Details::Allocator for T = "
59 << TypeNameTraits<T>::name () << endl;
60 AllocationLogger::resetAllocationCounts ();
61
62 typedef Teuchos::Details::Allocator<T> alloc_type;
63 alloc_type alloc;
64
65 typedef typename alloc_type::size_type size_type;
66
67 // At this point, we haven't allocated anything yet. The allocator
68 // does not track whatever memory it uses in its implementation.
69 TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
70
71 // We'll use this below.
72 size_type oldMaxAlloc = 0;
73
74 // Put the test in an inner scope, so that the std::vector gets
75 // deallocated before this test finishes. This lets us print
76 // whether deallocation succeeded.
77 {
78 const size_type numEntries = 10;
79
80 typedef std::vector<T, alloc_type> vec_type;
81 // C++14 defines a two-argument std::vector constructor (count,
82 // alloc), but C++11 only has a three-argument constructor that
83 // takes a count and the allocator. Thus, we need some default
84 // value T. I choose 22 because it is one plus the sum of
85 // integers from 1 to 10, inclusive. It's not a default value,
86 // like zero, and it's positive, so it works if T is unsigned.
87 // It also fits exactly in float and double.
88 T val = static_cast<T> (22);
89 vec_type vec (numEntries, val, alloc);
90
91 TEST_EQUALITY( vec.size (), numEntries );
92 TEST_EQUALITY_CONST( vec.capacity () >= vec.size (), true );
93
94 oldMaxAlloc = alloc.maxAllocInBytes ();
95 const size_type curAlloc = alloc.curAllocInBytes ();
96 const size_type expectedCurAlloc = numEntries * sizeof (T);
97
98 // We don't need strict equality, because the allocator may choose
99 // to allocate more memory than necessary (e.g., to stash
100 // additional information in each allocation).
101 TEST_EQUALITY_CONST( curAlloc >= expectedCurAlloc, true );
102 TEST_EQUALITY_CONST( oldMaxAlloc >= expectedCurAlloc, true );
103
104 // Make sure that the std::vector's constructor correctly filled
105 // it using val. We have to test this because std::vector defers
106 // to alloc_type::construct for this.
107 for (size_type k = 0; k < numEntries; ++k) {
108 TEST_EQUALITY( vec[k], val );
109 }
110 }
111
112 // At this point, alloc.curAlloc() should be zero, and
113 // alloc.maxAlloc() should not have changed.
114 const size_type newMaxAlloc = alloc.maxAllocInBytes ();
115 TEST_EQUALITY( oldMaxAlloc, newMaxAlloc );
116 TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
117
118 out << "Done with test!" << endl;
119}
120
121//
122// Repeat Test1, but with verbose logging on.
123//
124TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( Allocator, Test2, T )
125{
128 using std::endl;
129
130 Teuchos::OSTab tab0 (out);
131 out << "Test Teuchos::Details::Allocator for T = "
132 << TypeNameTraits<T>::name () << ", with verbose logging on" << endl;
133 AllocationLogger::resetAllocationCounts ();
134
135 typedef Teuchos::Details::Allocator<T> alloc_type;
136 // Tell the Allocator to track memory.
137 alloc_type alloc (true, true);
138
139 typedef typename alloc_type::size_type size_type;
140
141 // At this point, we haven't allocated anything yet. The allocator
142 // does not track whatever memory it uses in its implementation.
143 TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
144
145 // We'll use this below.
146 size_type oldMaxAlloc = 0;
147
148 // Put the test in an inner scope, so that the std::vector gets
149 // deallocated before this test finishes. This lets us print
150 // whether deallocation succeeded.
151 {
152 const size_type numEntries = 10;
153
154 typedef std::vector<T, alloc_type> vec_type;
155 // C++14 defines a two-argument std::vector constructor (count,
156 // alloc), but C++11 only has a three-argument constructor that
157 // takes a count and the allocator. Thus, we need some default
158 // value T. I choose 22 because it is one plus the sum of
159 // integers from 1 to 10, inclusive. It's not a default value,
160 // like zero, and it's positive, so it works if T is unsigned.
161 // It also fits exactly in float and double.
162 T val = static_cast<T> (22);
163 vec_type vec (numEntries, val, alloc);
164
165 TEST_EQUALITY( vec.size (), numEntries );
166 TEST_EQUALITY_CONST( vec.capacity () >= vec.size (), true );
167
168 oldMaxAlloc = alloc.maxAllocInBytes ();
169 const size_type curAlloc = alloc.curAllocInBytes ();
170 const size_type expectedCurAlloc = numEntries * sizeof (T);
171
172 // We don't need strict equality, because the allocator may choose
173 // to allocate more memory than necessary (e.g., to stash
174 // additional information in each allocation).
175 TEST_EQUALITY_CONST( curAlloc >= expectedCurAlloc, true );
176 TEST_EQUALITY_CONST( oldMaxAlloc >= expectedCurAlloc, true );
177
178 // Make sure that the std::vector's constructor correctly filled
179 // it using val. We have to test this because std::vector defers
180 // to alloc_type::construct for this.
181 for (size_type k = 0; k < numEntries; ++k) {
182 TEST_EQUALITY( vec[k], val );
183 }
184 }
185
186 // At this point, alloc.curAlloc() should be zero, and
187 // alloc.maxAlloc() should not have changed.
188 const size_type newMaxAlloc = alloc.maxAllocInBytes ();
189 TEST_EQUALITY( oldMaxAlloc, newMaxAlloc );
190 TEST_EQUALITY_CONST( alloc.curAllocInBytes (), static_cast<size_type> (0) );
191
192 out << "Done with test!" << endl;
193}
194
195//
196// Make sure that mixing std::vector<T> instances for different T
197// still gives the right current and max allocation numbers.
198//
199TEUCHOS_UNIT_TEST( Allocator, TestMixedTypes )
200{
202 using std::endl;
203
204 Teuchos::OSTab tab0 (out);
205 out << "Test Teuchos::Details::Allocator<T> for mixed T" << endl;
206 AllocationLogger::resetAllocationCounts ();
207
208 typedef Teuchos::Details::Allocator<int> int_alloc_type;
209 typedef int_alloc_type::size_type size_type;
210 const size_type numEntries = 10;
211 const size_type expectedMaxAlloc = numEntries * sizeof (int) + numEntries * sizeof (double);
212
213 // At this point, we haven't allocated anything yet.
214 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
215
216 {
217 std::vector<int, int_alloc_type> intVec (numEntries);
218
219 typedef Teuchos::Details::Allocator<double> double_alloc_type;
220 std::vector<double, double_alloc_type> dblVec (numEntries);
221
222 // Both std::vector types must report the same current and max total
223 // allocation sizes, since they share the same allocation mechanism.
224 TEST_EQUALITY( intVec.get_allocator ().curAllocInBytes (), dblVec.get_allocator ().curAllocInBytes () );
225 TEST_EQUALITY( intVec.get_allocator ().maxAllocInBytes (), dblVec.get_allocator ().maxAllocInBytes () );
226
227
228 TEST_EQUALITY_CONST( intVec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
229 TEST_EQUALITY_CONST( intVec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
230 }
231
232 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
233 TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
234
235 out << "Done with test!" << endl;
236}
237
238//
239// Make sure that the Allocator works for types T that do run-time
240// allocation. std::string is a good example.
241//
242// This is the test that shows why you CANNOT use "return new T[n]" to
243// implement allocate(), and "delete [] p" to implement deallocate().
244// (Try it on a Mac and watch your debug malloc complain that you're
245// trying to free something it never malloc'd.)
246//
247TEUCHOS_UNIT_TEST( Allocator, TestString )
248{
250 using std::endl;
251
252 Teuchos::OSTab tab0 (out);
253 out << "Test Teuchos::Details::Allocator<std::string>" << endl;
254 AllocationLogger::resetAllocationCounts ();
255
256 typedef Teuchos::Details::Allocator<std::string> string_alloc_type;
257 typedef string_alloc_type::size_type size_type;
258 const size_type numEntries = 10;
259 // Even though std::string itself does run-time allocation inside,
260 // this is still the correct max allocation for an array of
261 // std::string.
262 const size_type expectedMaxAlloc = numEntries * sizeof (std::string);
263
264 // At this point, we haven't allocated anything yet.
265 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
266
267 // First, try it without setting any of the strings.
268 {
269 std::vector<std::string, string_alloc_type> vec (numEntries);
270
271 TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
272 TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
273 }
274
275 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
276 TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
277
278 // Next, construct the std::vector, setting all entries to a string
279 // of nonzero length.
280 {
281 string_alloc_type alloc;
282 std::string val ("I'm a little teapot, short and stout.");
283 std::vector<std::string, string_alloc_type> vec (numEntries, val, alloc);
284
285 TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
286 TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
287 }
288
289 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
290 TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
291
292 // Next, construct the std::vector without setting any of the
293 // strings, then iterate through it and set the strings one by one
294 // to different values (that circumvents possible reference counting
295 // in std::string).
296 {
297 string_alloc_type alloc;
298 std::vector<std::string, string_alloc_type> vec (numEntries);
299
300 for (size_type k = 0; k < numEntries; ++k) {
301 std::ostringstream os;
302 os << "Current index: " << k;
303 vec[k] = os.str ();
304 }
305
306 TEST_EQUALITY_CONST( vec.get_allocator ().curAllocInBytes () >= expectedMaxAlloc, true );
307 TEST_EQUALITY_CONST( vec.get_allocator ().maxAllocInBytes () >= expectedMaxAlloc, true );
308 }
309
310 TEST_EQUALITY_CONST( AllocationLogger::curAllocInBytes (), static_cast<size_type> (0) );
311 TEST_EQUALITY_CONST( AllocationLogger::maxAllocInBytes () >= expectedMaxAlloc, true );
312
313 out << "Done with test!" << endl;
314}
315
316
317TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, int )
318TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, double )
319
320
321} // namespace (anonymous)
Declaration of Teuchos::Details::Allocator, a tracking and logging implementation of the C++ Standard...
#define TEST_EQUALITY_CONST(v1, v2)
Assert the equality of v1 and constant v2.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
Defines basic traits returning the name of a type in a portable and readable way.
Unit testing support.
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL(TEST_GROUP, TEST_NAME, TYPE)
Macro for defining a templated unit test with one template parameter.
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(TEST_GROUP, TEST_NAME, TYPE)
Instantiate a templated unit test with one template parameter.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
Logging implementation used by Allocator (see below).
Optional tracking allocator for Teuchos Memory Management classes.
Concrete serial communicator subclass.
Default traits class that just returns typeid(T).name().