LCOV - code coverage report
Current view: top level - xpcom/base - CountingAllocatorBase.h (source / functions) Hit Total Coverage
Test: output.info Lines: 14 29 48.3 %
Date: 2017-07-14 16:53:18 Functions: 6 21 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef CountingAllocatorBase_h
       8             : #define CountingAllocatorBase_h
       9             : 
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/Atomics.h"
      12             : #include "nsIMemoryReporter.h"
      13             : 
      14             : namespace mozilla {
      15             : 
      16             : // This CRTP class handles several details of wrapping allocators and should
      17             : // be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
      18             : // and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE.  The typical use is in a memory
      19             : // reporter for a particular third party library:
      20             : //
      21             : //   class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter>
      22             : //   {
      23             : //     ...
      24             : //     NS_IMETHOD
      25             : //     CollectReports(nsIHandleReportCallback* aHandleReport,
      26             : //                    nsISupports* aData, bool aAnonymize) override
      27             : //     {
      28             : //        MOZ_COLLECT_REPORT(
      29             : //          "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
      30             : //          MemoryAllocated(),
      31             : //          "A description of what we are reporting.");
      32             : //
      33             : //        return NS_OK;
      34             : //     }
      35             : //   };
      36             : //
      37             : //   ...somewhere later in the code...
      38             : //   SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
      39             : //                                MyMemoryReporter::CountingFree);
      40             : template<typename T>
      41             : class CountingAllocatorBase
      42             : {
      43             : public:
      44           6 :   CountingAllocatorBase()
      45             :   {
      46             : #ifdef DEBUG
      47             :     // There must be only one instance of this class, due to |sAmount| being
      48             :     // static.
      49             :     static bool hasRun = false;
      50           6 :     MOZ_ASSERT(!hasRun);
      51           6 :     hasRun = true;
      52             : #endif
      53           6 :   }
      54             : 
      55             :   static size_t
      56           0 :   MemoryAllocated()
      57             :   {
      58           0 :     return sAmount;
      59             :   }
      60             : 
      61             :   static void*
      62          82 :   CountingMalloc(size_t size)
      63             :   {
      64          82 :     void* p = malloc(size);
      65          82 :     sAmount += MallocSizeOfOnAlloc(p);
      66          82 :     return p;
      67             :   }
      68             : 
      69             :   static void*
      70           0 :   CountingCalloc(size_t nmemb, size_t size)
      71             :   {
      72           0 :     void* p = calloc(nmemb, size);
      73           0 :     sAmount += MallocSizeOfOnAlloc(p);
      74           0 :     return p;
      75             :   }
      76             : 
      77             :   static void*
      78           0 :   CountingRealloc(void* p, size_t size)
      79             :   {
      80           0 :     size_t oldsize = MallocSizeOfOnFree(p);
      81           0 :     void *pnew = realloc(p, size);
      82           0 :     if (pnew) {
      83           0 :       size_t newsize = MallocSizeOfOnAlloc(pnew);
      84           0 :       sAmount += newsize - oldsize;
      85           0 :     } else if (size == 0) {
      86             :       // We asked for a 0-sized (re)allocation of some existing pointer
      87             :       // and received NULL in return.  0-sized allocations are permitted
      88             :       // to either return NULL or to allocate a unique object per call (!).
      89             :       // For a malloc implementation that chooses the second strategy,
      90             :       // that allocation may fail (unlikely, but possible).
      91             :       //
      92             :       // Given a NULL return value and an allocation size of 0, then, we
      93             :       // don't know if that means the original pointer was freed or if
      94             :       // the allocation of the unique object failed.  If the original
      95             :       // pointer was freed, then we have nothing to do here.  If the
      96             :       // allocation of the unique object failed, the original pointer is
      97             :       // still valid and we ought to undo the decrement from above.
      98             :       // However, we have no way of knowing how the underlying realloc
      99             :       // implementation is behaving.  Assuming that the original pointer
     100             :       // was freed is the safest course of action.  We do, however, need
     101             :       // to note that we freed memory.
     102           0 :       sAmount -= oldsize;
     103             :     } else {
     104             :       // realloc failed.  The amount allocated hasn't changed.
     105             :     }
     106           0 :     return pnew;
     107             :   }
     108             : 
     109             :   // Some library code expects that realloc(x, 0) will free x, which is not
     110             :   // the behavior of the version of jemalloc we're using, so this wrapped
     111             :   // version of realloc is needed.
     112             :   static void*
     113             :   CountingFreeingRealloc(void* p, size_t size)
     114             :   {
     115             :     if (size == 0) {
     116             :       CountingFree(p);
     117             :       return nullptr;
     118             :     }
     119             :     return CountingRealloc(p, size);
     120             :   }
     121             : 
     122             :   static void
     123          19 :   CountingFree(void* p)
     124             :   {
     125          19 :     sAmount -= MallocSizeOfOnFree(p);
     126          19 :     free(p);
     127          19 :   }
     128             : 
     129             : private:
     130             :   // |sAmount| can be (implicitly) accessed by multiple threads, so it
     131             :   // must be thread-safe.
     132             :   static Atomic<size_t> sAmount;
     133             : 
     134          82 :   MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
     135          19 :   MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
     136             : };
     137             : 
     138             : } // namespace mozilla
     139             : 
     140             : #endif // CountingAllocatorBase_h

Generated by: LCOV version 1.13