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.
Default traits class that just returns typeid(T).name().
Tabbing class for helping to create formated, indented output for a basic_FancyOStream object.