diff --git a/groups/bal/balst/balst_stacktracetestallocator.cpp b/groups/bal/balst/balst_stacktracetestallocator.cpp index a42361f371..d7e8410bb3 100644 --- a/groups/bal/balst/balst_stacktracetestallocator.cpp +++ b/groups/bal/balst/balst_stacktracetestallocator.cpp @@ -266,6 +266,7 @@ StackTraceTestAllocator::StackTraceTestAllocator( bslma::Allocator *basicAllocator) : d_magic(k_STACK_TRACE_TEST_ALLOCATOR_MAGIC) , d_numBlocksInUse(0) +, d_numAllocations(0) , d_blocks(0) , d_mutex() , d_name("") @@ -295,6 +296,7 @@ StackTraceTestAllocator::StackTraceTestAllocator( bslma::Allocator *basicAllocator) : d_magic(k_STACK_TRACE_TEST_ALLOCATOR_MAGIC) , d_numBlocksInUse(0) +, d_numAllocations(0) , d_blocks(0) , d_mutex() , d_name("") @@ -391,6 +393,7 @@ void *StackTraceTestAllocator::allocate(size_type size) BSLS_ASSERT(0 == ((UintPtr) ret & ((sizeof(void *) - 1) | lowBits))); ++d_numBlocksInUse; + ++d_numAllocations; return ret; } diff --git a/groups/bal/balst/balst_stacktracetestallocator.h b/groups/bal/balst/balst_stacktracetestallocator.h index 31c7ef2fc6..b2048b3866 100644 --- a/groups/bal/balst/balst_stacktracetestallocator.h +++ b/groups/bal/balst/balst_stacktracetestallocator.h @@ -31,6 +31,7 @@ BSLS_IDENT("$Id: $") // ( balst::StackTraceTestAllocator ) // `------------------------------' // | ctor/dtor +// | numAllocations // | numBlocksInUse // | reportBlocksInUse // | setFailureHandler @@ -527,6 +528,10 @@ class StackTraceTestAllocator : public bdlma::ManagedAllocator { bsls::AtomicInt d_numBlocksInUse; // number of allocated // blocks currently unfreed + bsls::AtomicInt64 d_numAllocations; // number of alloctions that + // have occurred since + // creation + BlockHeader *d_blocks; // list of allocated, // unfreed blocks @@ -677,6 +682,11 @@ class StackTraceTestAllocator : public bdlma::ManagedAllocator { // Return a reference to the function that will be called when a // failure is observered. + bsls::Types::Int64 numAllocations() const; + // Return the number of allocations from this object that have occurred + // since creation. Note that this does not count allocations of 0 + // length, which return null pointers. + bsl::size_t numBlocksInUse() const; // Return the number of blocks currently allocated from this object. @@ -705,6 +715,12 @@ bsl::size_t StackTraceTestAllocator::numBlocksInUse() const return d_numBlocksInUse; } +inline +bsls::Types::Int64 StackTraceTestAllocator::numAllocations() const +{ + return d_numAllocations; +} + } // close package namespace } // close enterprise namespace diff --git a/groups/bal/balst/balst_stacktracetestallocator.t.cpp b/groups/bal/balst/balst_stacktracetestallocator.t.cpp index e0901e6ddc..8f6ba605a2 100644 --- a/groups/bal/balst/balst_stacktracetestallocator.t.cpp +++ b/groups/bal/balst/balst_stacktracetestallocator.t.cpp @@ -1513,6 +1513,8 @@ int main(int argc, char *argv[]) //: was filled with when allocated. //: o Check the 'numBlocksInUse' accessor to verify that it properly //: tracks its expected value. + //: o Check the 'numAllocations' accessor to verify that it properly + //: tracks its expected value. //--------------------------------------------------------------------- if (verbose) cout << "ALIGNMENT & RANDOM ALLOCATE / FREE TEST\n" @@ -1538,119 +1540,133 @@ int main(int argc, char *argv[]) const int ptrAlign = bsls::AlignmentUtil::calculateAlignmentFromSize( sizeof(void *)); - memset(blocks, 0, sizeof(blocks)); - for (int i = 0; i < MAX_NUM_BLOCKS; ++i) { - Block& s = blocks[i]; - s.d_len = i / 2; - - // 'AlignmentUtil' fails if passed an argument of 0 + // The 'ia' loop is to create 'Obj ta' with both c'tors. - s.d_align = !s.d_len - ? 8 - : bsls::AlignmentUtil::calculateAlignmentFromSize( - s.d_len); - s.d_align = bsl::max(s.d_align, ptrAlign); + for (int ia = 0; ia < 2; ++ia) { + memset(blocks, 0, sizeof(blocks)); + for (int i = 0; i < MAX_NUM_BLOCKS; ++i) { + Block& s = blocks[i]; + s.d_len = i / 2; - // verify one bit of alignment set - - ASSERT(0 == (s.d_align & (s.d_align - 1))); - } + // 'AlignmentUtil' fails if passed an argument of 0 - Obj ta; - int randNum; - bdlb::Random::generate15(&randNum, 987654321); + s.d_align = !s.d_len + ? 8 + : bsls::AlignmentUtil::calculateAlignmentFromSize( + s.d_len); + s.d_align = bsl::max(s.d_align, ptrAlign); - // allocate 100% of the blocks, in random order + // verify one bit of alignment set - for (int i = 0; i < MAX_NUM_BLOCKS; ++i) { - int index = bdlb::Random::generate15(&randNum) % MAX_NUM_BLOCKS; - while (blocks[index].d_alloced) { - index = (index + 1) % MAX_NUM_BLOCKS; + ASSERT(0 == (s.d_align & (s.d_align - 1))); } - Block& s = blocks[index]; - - s.d_ptr = (char *) ta.allocate(s.d_len); - s.d_alloced = true; - s.d_fill = (char) bdlb::Random::generate15(&randNum); - memset(s.d_ptr, s.d_fill, s.d_len); - - ASSERT(!s.d_ptr == !s.d_len); - - // verify block aligned + Obj ta0; + Obj ta1(20); + Obj& ta = 0 == ia ? ta0 : ta1; + int randNum; + bdlb::Random::generate15(&randNum, 987654321); - LOOP3_ASSERT((void *) s.d_ptr, s.d_len, s.d_align, - 0 == ((UintPtr) s.d_ptr & (s.d_align - 1))); - } - int numBlocks = MAX_NUM_BLOCKS; - int numBlocksInUse = numBlocks - 2; - ASSERT((int) ta.numBlocksInUse() == numBlocksInUse); - - // Now go around chosing blocks at random to be allocated or freed in - // random order. - - for (int i = 0; i < ITERATIONS; ++i) { - const bool alloc = numBlocks > 3 * QUARTER_BLOCKS - ? false - : numBlocks < QUARTER_BLOCKS - ? true - : (bdlb::Random::generate15(&randNum) & 1); - - // Steer the # of blocks allocated to be at around half the - // slots, give or take a quarter. - - int index = bdlb::Random::generate15(&randNum) % MAX_NUM_BLOCKS; - while (alloc == blocks[index].d_alloced) { - index = (index + 1) % MAX_NUM_BLOCKS; - } - Block& s = blocks[index]; + // allocate 100% of the blocks, in random order - if (alloc) { - // allocate + int numAllocations = 0; + for (int i = 0; i < MAX_NUM_BLOCKS; ++i) { + int index = + bdlb::Random::generate15(&randNum) % MAX_NUM_BLOCKS; + while (blocks[index].d_alloced) { + index = (index + 1) % MAX_NUM_BLOCKS; + } - ASSERT(!s.d_alloced); - ASSERT(!s.d_ptr); + Block& s = blocks[index]; s.d_ptr = (char *) ta.allocate(s.d_len); s.d_alloced = true; - ++numBlocks; + s.d_fill = (char) bdlb::Random::generate15(&randNum); if (s.d_ptr) { - ++numBlocksInUse; + memset(s.d_ptr, s.d_fill, s.d_len); + ++numAllocations; } - ASSERT(!s.d_ptr == !s.d_len); - s.d_fill = (char) bdlb::Random::generate15(&randNum); - memset(s.d_ptr, s.d_fill, s.d_len); // verify block aligned LOOP3_ASSERT((void *) s.d_ptr, s.d_len, s.d_align, 0 == ((UintPtr) s.d_ptr & (s.d_align - 1))); } - else { - // free + int numBlocksInUse = MAX_NUM_BLOCKS - 2; + ASSERT(numAllocations == numBlocksInUse); + ASSERT((int) ta.numBlocksInUse() == numBlocksInUse); + ASSERT(ta.numAllocations() == numAllocations); - ASSERT(s.d_alloced); - ASSERT(!s.d_ptr == !s.d_len); + // Now go around chosing blocks at random to be allocated or freed + // in random order. + + for (int i = 0; i < ITERATIONS; ++i) { + const bool alloc = numBlocksInUse > 3 * QUARTER_BLOCKS + ? false + : numBlocksInUse < QUARTER_BLOCKS + ? true + : (bdlb::Random::generate15(&randNum) & 1); + + // Steer the # of blocks allocated to be at around half the + // slots, give or take a quarter. + + int index = + bdlb::Random::generate15(&randNum) % MAX_NUM_BLOCKS; + while (alloc == blocks[index].d_alloced) { + index = (index + 1) % MAX_NUM_BLOCKS; + } + Block& s = blocks[index]; + + if (alloc) { + // allocate + + ASSERT(!s.d_alloced); + ASSERT(!s.d_ptr); + + s.d_ptr = (char *) ta.allocate(s.d_len); + s.d_alloced = true; + + ASSERT(!s.d_ptr == !s.d_len); + s.d_fill = (char) bdlb::Random::generate15(&randNum); + if (s.d_ptr) { + ++numBlocksInUse; + ++numAllocations; + memset(s.d_ptr, s.d_fill, s.d_len); + } - char *end = s.d_ptr + s.d_len; - char *f = bsl::find_if(s.d_ptr, end, TC::NotEqual(s.d_fill)); - ASSERT(f == end); - memset(s.d_ptr, ~s.d_fill, s.d_len); - - ta.deallocate(s.d_ptr); - s.d_ptr = 0; - s.d_alloced = false; - --numBlocks; - if (s.d_len) { - --numBlocksInUse; + // verify block aligned + + LOOP3_ASSERT((void *) s.d_ptr, s.d_len, s.d_align, + 0 == ((UintPtr) s.d_ptr & (s.d_align - 1))); + } + else { + // free + + ASSERT(s.d_alloced); + ASSERT(!s.d_ptr == !s.d_len); + + char *end = s.d_ptr + s.d_len; + char *f = + bsl::find_if(s.d_ptr, end, TC::NotEqual(s.d_fill)); + ASSERT(f == end); + memset(s.d_ptr, ~s.d_fill, s.d_len); + + ta.deallocate(s.d_ptr); + s.d_ptr = 0; + s.d_alloced = false; + if (s.d_len) { + --numBlocksInUse; + } } + + ASSERT(numBlocksInUse <= numAllocations); + ASSERT((int) ta.numBlocksInUse() == numBlocksInUse); + ASSERT(ta.numAllocations() == numAllocations); } - ASSERT((int) ta.numBlocksInUse() == numBlocksInUse); + ta.release(); } - - ta.release(); } break; case 16: { //---------------------------------------------------------------------