Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
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 
48 namespace { // (anonymous)
49 
50 
51 TEUCHOS_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 //
124 TEUCHOS_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 //
199 TEUCHOS_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 //
247 TEUCHOS_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 
317 TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, int )
318 TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( Allocator, Test1, double )
319 
320 
321 } // namespace (anonymous)
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL(TEST_GROUP, TEST_NAME, TYPE)
Macro for defining a templated unit test with one template parameter.
#define TEST_EQUALITY(v1, v2)
Assert the equality of v1 and v2.
#define TEUCHOS_UNIT_TEST(TEST_GROUP, TEST_NAME)
Macro for defining a (non-templated) unit test.
Optional tracking allocator for Teuchos Memory Management classes.
Logging implementation used by Allocator (see below).
Tabbing class for helping to create formated, indented output for a basic_FancyOStream object...
Unit testing support.
#define TEST_EQUALITY_CONST(v1, v2)
Assert the equality of v1 and constant v2.
Default traits class that just returns typeid(T).name().
#define TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(TEST_GROUP, TEST_NAME, TYPE)
Instantiate a templated unit test with one template parameter.
Defines basic traits returning the name of a type in a portable and readable way. ...
Declaration of Teuchos::Details::Allocator, a tracking and logging implementation of the C++ Standard...