BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_countingallocator.h
Go to the documentation of this file.
1/// @file bdlma_countingallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_countingallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_COUNTINGALLOCATOR
9#define INCLUDED_BDLMA_COUNTINGALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_countingallocator bdlma_countingallocator
15/// @brief Provide a memory allocator that counts allocated bytes.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_countingallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_countingallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_countingallocator-classes"> Classes </a>
26/// * <a href="#bdlma_countingallocator-description"> Description </a>
27/// * <a href="#bdlma_countingallocator-byte-counts"> Byte Counts </a>
28/// * <a href="#bdlma_countingallocator-thread-safety"> Thread Safety </a>
29/// * <a href="#bdlma_countingallocator-usage"> Usage </a>
30/// * <a href="#bdlma_countingallocator-example-1-tracking-a-container-s-dynamic-memory-use"> Example 1: Tracking a Container's Dynamic Memory Use </a>
31///
32/// # Purpose {#bdlma_countingallocator-purpose}
33/// Provide a memory allocator that counts allocated bytes.
34///
35/// # Classes {#bdlma_countingallocator-classes}
36///
37/// - bdlma::CountingAllocator: concrete allocator that counts allocated bytes
38///
39/// @see bslma_allocator, bslma_testallocator
40///
41/// # Description {#bdlma_countingallocator-description}
42/// This component provides a special-purpose counting allocator,
43/// `bdlma::CountingAllocator`, that implements the `bslma::Allocator` protocol
44/// and provides instrumentation to track: (1) the number of bytes currently in
45/// use (`numBytesInUse`), and (2) the cumulative number of bytes that have ever
46/// been allocated (`numBytesTotal`). The accumulated statistics are based
47/// solely on the number of bytes requested in calls to the `allocate` method.
48/// A `print` method is provided to output the current state of the allocator's
49/// byte counts to a specified `bsl::ostream`:
50/// @code
51/// ,------------------------.
52/// ( bdlma::CountingAllocator )
53/// `------------------------'
54/// | ctor/dtor
55/// | numBytesInUse
56/// | numBytesTotal
57/// | name
58/// | print
59/// V
60/// ,----------------.
61/// ( bslma::Allocator )
62/// `----------------'
63/// allocate
64/// deallocate
65/// @endcode
66/// Like many other allocators, `bdlma::CountingAllocator` relies on the
67/// currently installed default allocator (see @ref bslma_default ) at construction.
68/// Clients may, however, override this allocator by supplying (at construction)
69/// any other allocator implementing the `bslma::Allocator` protocol provided
70/// that it is fully thread-safe.
71///
72/// Note that a `bdlma::CountingAllocator` necessarily incurs some overhead in
73/// order to provide its byte-counting functionality. However, this overhead is
74/// *substantially* less than that incurred by the `bslma::TestAllocator` (see
75/// @ref bslma_testallocator ), which keeps track of the same two statistics that
76/// are maintained by a `bdlma::CountingAllocator`. Consequently, use of a
77/// `bdlma::CountingAllocator` may be appropriate in cases where the overhead of
78/// `bslma::TestAllocator` is too onerous. In particular, a counting allocator
79/// may be suitable even for production use in certain situations, whereas the
80/// test allocator is not intended for production use under any circumstance.
81///
82/// ## Byte Counts {#bdlma_countingallocator-byte-counts}
83///
84///
85/// The two byte counts maintained by `bdlma::CountingAllocator` are initialized
86/// to 0 at construction and increased with each call to `allocate` by `size`,
87/// i.e., by the actual number of bytes requested. Each call to `deallocate`
88/// decreases the `numBytesInUse` count by the same amount by which the byte
89/// count was increased in the original `allocate` call. The number of bytes
90/// currently in use is returned by `numBytesInUse` and the total number of
91/// bytes ever allocated is returned by `numBytesTotal`.
92///
93/// ## Thread Safety {#bdlma_countingallocator-thread-safety}
94///
95///
96/// The `bdlma::CountingAllocator` class is fully thread-safe (see
97/// @ref bsldoc_glossary ) provided that the underlying allocator (established at
98/// construction) is fully thread-safe.
99///
100/// ## Usage {#bdlma_countingallocator-usage}
101///
102///
103/// This section illustrates intended use of this component.
104///
105/// ## Example 1: Tracking a Container's Dynamic Memory Use {#bdlma_countingallocator-example-1-tracking-a-container-s-dynamic-memory-use}
106///
107///
108/// In this example, we demonstrate how a counting allocator may be used to
109/// track the amount of dynamic memory used by a container. The container used
110/// for illustration is `DoubleStack`, a stack of out-of-place `double` values.
111///
112/// First, we show the interface of the `DoubleStack` class:
113/// @code
114/// // doublestack.h
115///
116/// class DoubleStack {
117/// // This class implements a stack of out-of-place 'double' values.
118///
119/// // DATA
120/// double **d_stack_p; // dynamically allocated array of
121/// // 'd_capacity' elements
122///
123/// int d_capacity; // physical capacity of the stack
124/// // (in elements)
125///
126/// int d_length; // logical index of next available
127/// // stack element
128///
129/// bslma::Allocator *d_allocator_p; // memory allocator (held, not
130/// // owned)
131///
132/// // NOT IMPLEMENTED
133/// DoubleStack(const DoubleStack&);
134/// DoubleStack& operator=(const DoubleStack&);
135///
136/// private:
137/// // PRIVATE MANIPULATORS
138/// void increaseCapacity();
139/// // Increase the capacity of this stack by at least one element.
140///
141/// public:
142/// // CREATORS
143/// explicit
144/// DoubleStack(bslma::Allocator *basicAllocator = 0);
145/// // Create a stack for 'double' values having an initial capacity to
146/// // hold one element. Optionally specify a 'basicAllocator' used to
147/// // supply memory. If 'basicAllocator' is 0, the currently
148/// // installed default allocator is used.
149///
150/// ~DoubleStack();
151/// // Delete this object.
152///
153/// // MANIPULATORS
154/// void push(double value);
155/// // Add the specified 'value' to the top of this stack.
156///
157/// void pop();
158/// // Remove the element at the top of this stack. The behavior is
159/// // undefined unless this stack is non-empty.
160///
161/// // ACCESSORS
162/// // ...
163/// };
164/// @endcode
165/// Next, we show the (elided) implementation of `DoubleStack`.
166///
167/// The default constructor creates a stack having the capacity for one element
168/// (the implementation of the destructor is not shown):
169/// @code
170/// // doublestack.cpp
171/// // ...
172///
173/// // TYPES
174/// enum { k_INITIAL_CAPACITY = 1, k_GROWTH_FACTOR = 2 };
175///
176/// // CREATORS
177/// DoubleStack::DoubleStack(bslma::Allocator *basicAllocator)
178/// : d_stack_p(0)
179/// , d_capacity(k_INITIAL_CAPACITY)
180/// , d_length(0)
181/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
182/// {
183/// d_stack_p = (double **)
184/// d_allocator_p->allocate(d_capacity * sizeof *d_stack_p);
185/// }
186/// @endcode
187/// The `push` method first ensures that the array has sufficient capacity to
188/// accommodate an additional value, then allocates a block in which to store
189/// that value:
190/// @code
191/// // MANIPULATORS
192/// void DoubleStack::push(double value)
193/// {
194/// if (d_length >= d_capacity) {
195/// increaseCapacity();
196/// }
197/// double *stackValue = (double *)d_allocator_p->allocate(sizeof(double));
198/// *stackValue = value;
199/// d_stack_p[d_length] = stackValue;
200/// ++d_length;
201/// }
202/// @endcode
203/// The `pop` method asserts that the stack is not empty before deallocating the
204/// block used to store the element at the top of the stack:
205/// @code
206/// void DoubleStack::pop()
207/// {
208/// BSLS_ASSERT(0 < d_length);
209///
210/// d_allocator_p->deallocate(d_stack_p[d_length - 1]);
211/// --d_length;
212/// }
213/// @endcode
214/// The `push` method (above) made use of the private `increaseCapacity` method,
215/// which, in turn, makes use of the `reallocate` helper function (`static` to
216/// the `.cpp` file). Note that `increaseCapacity` (below) increases the
217/// capacity of the `double *` array by a factor of 2 each time that it is
218/// called:
219/// @code
220/// // HELPER FUNCTIONS
221/// static
222/// void reallocate(double ***array,
223/// int newCapacity,
224/// int length,
225/// bslma::Allocator *allocator)
226/// // Reallocate memory in the specified 'array' to accommodate the
227/// // specified 'newCapacity' elements using the specified 'allocator'.
228/// // The specified 'length' number of leading elements are preserved.
229/// // The behavior is undefined unless 'newCapacity > length'.
230/// {
231/// BSLS_ASSERT(newCapacity > length);
232///
233/// double **tmp = *array;
234/// *array = (double **)allocator->allocate(newCapacity * sizeof **array);
235/// bsl::memcpy(*array, tmp, length * sizeof **array); // commit
236/// allocator->deallocate(tmp);
237/// }
238///
239/// // PRIVATE MANIPULATORS
240/// void DoubleStack::increaseCapacity()
241/// {
242/// const int newCapacity = d_capacity * k_GROWTH_FACTOR;
243/// // reallocate can throw
244/// reallocate(&d_stack_p, newCapacity, d_length, d_allocator_p);
245/// d_capacity = newCapacity; // commit
246/// }
247/// @endcode
248/// Now, we are ready to employ a `CountingAllocator` to illustrate the dynamic
249/// memory use of `DoubleStack`. We first define two constants that facilitate
250/// portability of this example across 32- and 64-bit platforms:
251/// @code
252/// const int DBLSZ = sizeof(double);
253/// const int PTRSZ = sizeof(double *);
254/// @endcode
255/// First, we define a `CountingAllocator`, `ca`. At construction, a counting
256/// allocator can be configured with an optional name and an optional allocator.
257/// In this case, we give `ca` a name to distinguish it from other counting
258/// allocators, but settle for using the default allocator:
259/// @code
260/// bdlma::CountingAllocator ca("'DoubleStack' Allocator");
261/// @endcode
262/// Next, we create a `DoubleStack`, supplying it with `ca`, and assert the
263/// expected memory use incurred by the default constructor:
264/// @code
265/// DoubleStack stack(&ca);
266/// assert(1 * PTRSZ == ca.numBytesInUse());
267/// assert(1 * PTRSZ == ca.numBytesTotal());
268/// @endcode
269/// Next, we push an element onto the stack. The first push incurs an
270/// additional allocation to store (out-of-place) the value being inserted:
271/// @code
272/// stack.push(1.54); assert(1 * PTRSZ + 1 * DBLSZ == ca.numBytesInUse());
273/// assert(1 * PTRSZ + 1 * DBLSZ == ca.numBytesTotal());
274/// @endcode
275/// Next, we push a second element onto the stack. In this case, two
276/// allocations result, one due to the resizing of the internal array and one
277/// required to store the new value out-of-place:
278/// @code
279/// stack.push(0.99); assert(2 * PTRSZ + 2 * DBLSZ == ca.numBytesInUse());
280/// assert(3 * PTRSZ + 2 * DBLSZ == ca.numBytesTotal());
281/// @endcode
282/// Next, we pop the top-most element from the stack. The number of bytes in
283/// use decreases by the amount used to store the popped element out-of-place:
284/// @code
285/// stack.pop(); assert(2 * PTRSZ + 1 * DBLSZ == ca.numBytesInUse());
286/// assert(3 * PTRSZ + 2 * DBLSZ == ca.numBytesTotal());
287/// @endcode
288/// Finally, we print the state of `ca` to standard output:
289/// @code
290/// ca.print(bsl::cout);
291/// @endcode
292/// which displays the following on a 32-bit platform:
293/// @code
294/// ----------------------------------------
295/// Counting Allocator State
296/// ----------------------------------------
297/// Allocator name: 'DoubleStack' Allocator
298/// Bytes in use: 16
299/// Bytes in total: 28
300/// @endcode
301/// @}
302/** @} */
303/** @} */
304
305/** @addtogroup bdl
306 * @{
307 */
308/** @addtogroup bdlma
309 * @{
310 */
311/** @addtogroup bdlma_countingallocator
312 * @{
313 */
314
315#include <bdlscm_version.h>
316
317#include <bslma_allocator.h>
318
319#include <bsls_atomic.h>
320#include <bsls_keyword.h>
321#include <bsls_types.h>
322
323#include <bsl_iosfwd.h>
324
325
326namespace bdlma {
327
328 // =======================
329 // class CountingAllocator
330 // =======================
331
332/// This class defines a concrete "counting" allocator mechanism that
333/// implements the `bslma::Allocator` protocol, and provides instrumentation
334/// to track: (1) the number of bytes currently in use, and (2) the
335/// cumulative number of bytes that have ever been allocated. The
336/// accumulated statistics are based solely on the number of bytes requested
337/// (see `allocate`).
338///
339/// Note that, like many other allocators, this allocator relies on the
340/// currently installed default allocator (see @ref bslma_default ). Clients
341/// may, however, override this allocator by supplying (at construction) any
342/// other allocator implementing the `bslma::Allocator` protocol provided
343/// that it is fully thread-safe.
344///
345/// See @ref bdlma_countingallocator
347
348 // DATA
349 const char *d_name_p; // optionally specified name of this
350 // allocator object (or 0)
351
352 bsls::AtomicInt64 d_numBytesInUse; // number of bytes currently allocated
353 // from this object
354
355 bsls::AtomicInt64 d_numBytesTotal; // cumulative number of bytes ever
356 // allocated from this object
357
358 bslma::Allocator *d_allocator_p; // memory allocator (held, not owned)
359
360 private:
361 // NOT IMPLEMENTED
363 CountingAllocator& operator=(const CountingAllocator&);
364
365 public:
366 // CREATORS
367
368 explicit
370 /// Create a counting allocator. Optionally specify a `name`
371 /// (associated with this object) to be included in messages output by
372 /// the `print` method, thereby distinguishing this counting allocator
373 /// from others that might be used in the same program. If `name` is 0
374 /// (or not specified), no distinguishing name is incorporated in
375 /// `print` output. Optionally specify a `basicAllocator` used to
376 /// supply memory. If `basicAllocator` is 0, the currently installed
377 /// default allocator is used.
378 explicit
379 CountingAllocator(const char *name, bslma::Allocator *basicAllocator = 0);
380
381 /// Destroy this allocator object. Note that destroying this allocator
382 /// has no effect on any outstanding allocated memory.
384
385 // MANIPULATORS
386
387 /// Return a newly-allocated block of memory of the specified `size` (in
388 /// bytes). If `size` is 0, a null pointer is returned with no other
389 /// effect (e.g., on allocation statistics). Otherwise, invoke the
390 /// `allocate` method of the allocator supplied at construction, and
391 /// increment the number of currently (and cumulatively) allocated bytes
392 /// by `size`.
394
395 /// Return the memory block at the specified `address` back to this
396 /// allocator. If `address` is 0, this function has no effect (e.g., on
397 /// allocation statistics). Otherwise, decrease the number of currently
398 /// allocated bytes by the size originally requested for the block. The
399 /// behavior is undefined unless `address` was allocated using this
400 /// allocator object and has not already been deallocated.
402
403 // ACCESSORS
404
405 /// Return the name of this counting allocator, or 0 if no name was
406 /// specified at construction.
407 const char *name() const;
408
409 /// Return the number of bytes currently allocated from this object.
410 /// Note that `numBytesInUse() <= numBytesTotal()`.
411 bsls::Types::Int64 numBytesInUse() const;
412
413 /// Return the cumulative number of bytes ever allocated from this
414 /// object. Note that `numBytesInUse() <= numBytesTotal()`.
415 bsls::Types::Int64 numBytesTotal() const;
416
417 /// Write the accumulated state information held in this allocator to
418 /// the specified `stream` in some reasonable (multi-line) format, and
419 /// return a reference to `stream`.
420 bsl::ostream& print(bsl::ostream& stream) const;
421};
422
423// ============================================================================
424// INLINE DEFINITIONS
425// ============================================================================
426
427 // -----------------------
428 // class CountingAllocator
429 // -----------------------
430
431// ACCESSORS
432inline
433const char *CountingAllocator::name() const
434{
435 return d_name_p;
436}
437
438inline
440{
441 return d_numBytesInUse.loadRelaxed();
442}
443
444inline
446{
447 return d_numBytesTotal.loadRelaxed();
448}
449
450} // close package namespace
451
452
453#endif
454
455// ----------------------------------------------------------------------------
456// Copyright 2016 Bloomberg Finance L.P.
457//
458// Licensed under the Apache License, Version 2.0 (the "License");
459// you may not use this file except in compliance with the License.
460// You may obtain a copy of the License at
461//
462// http://www.apache.org/licenses/LICENSE-2.0
463//
464// Unless required by applicable law or agreed to in writing, software
465// distributed under the License is distributed on an "AS IS" BASIS,
466// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
467// See the License for the specific language governing permissions and
468// limitations under the License.
469// ----------------------------- END-OF-FILE ----------------------------------
470
471/** @} */
472/** @} */
473/** @} */
Definition bdlma_countingallocator.h:346
bsl::ostream & print(bsl::ostream &stream) const
void * allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE
CountingAllocator(bslma::Allocator *basicAllocator=0)
const char * name() const
Definition bdlma_countingallocator.h:433
bsls::Types::Int64 numBytesTotal() const
Definition bdlma_countingallocator.h:445
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
~CountingAllocator() BSLS_KEYWORD_OVERRIDE
CountingAllocator(const char *name, bslma::Allocator *basicAllocator=0)
bsls::Types::Int64 numBytesInUse() const
Definition bdlma_countingallocator.h:439
Definition bslma_allocator.h:457
std::size_t size_type
Definition bslma_allocator.h:499
Definition bsls_atomic.h:892
Types::Int64 loadRelaxed() const
Definition bsls_atomic.h:1914
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition bdlma_alignedallocator.h:276
Definition bdlb_printmethods.h:283
Definition bdlt_iso8601util.h:691
long long Int64
Definition bsls_types.h:132