LCOV - code coverage report
Current view: top level - xpcom/base - CodeAddressService.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 41 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
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 CodeAddressService_h__
       8             : #define CodeAddressService_h__
       9             : 
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/HashFunctions.h"
      12             : #include "mozilla/IntegerPrintfMacros.h"
      13             : #include "mozilla/MemoryReporting.h"
      14             : #include "mozilla/Types.h"
      15             : 
      16             : #include "mozilla/StackWalk.h"
      17             : 
      18             : namespace mozilla {
      19             : 
      20             : // This class is used to print details about code locations.
      21             : //
      22             : // |StringTable| must implement an Intern() method that returns an interned
      23             : // copy of the string that was passed in, as well as a standard
      24             : // SizeOfExcludingThis() method.
      25             : //
      26             : // |StringAlloc| must implement |copy| and |free|. |copy| copies a string,
      27             : // while |free| is used to free strings created by |copy|.
      28             : //
      29             : // |DescribeCodeAddressLock| is needed when the callers may be holding a lock
      30             : // used by MozDescribeCodeAddress.  |DescribeCodeAddressLock| must implement
      31             : // static methods IsLocked(), Unlock() and Lock().
      32             : template <class StringTable,
      33             :           class StringAlloc,
      34             :           class DescribeCodeAddressLock>
      35           0 : class CodeAddressService
      36             : {
      37             :   // GetLocation() is the key function in this class.  It's basically a wrapper
      38             :   // around MozDescribeCodeAddress.
      39             :   //
      40             :   // However, MozDescribeCodeAddress is very slow on some platforms, and we
      41             :   // have lots of repeated (i.e. same PC) calls to it.  So we do some caching
      42             :   // of results.  Each cached result includes two strings (|mFunction| and
      43             :   // |mLibrary|), so we also optimize them for space in the following ways.
      44             :   //
      45             :   // - The number of distinct library names is small, e.g. a few dozen.  There
      46             :   //   is lots of repetition, especially of libxul.  So we intern them in their
      47             :   //   own table, which saves space over duplicating them for each cache entry.
      48             :   //
      49             :   // - The number of distinct function names is much higher, so we duplicate
      50             :   //   them in each cache entry.  That's more space-efficient than interning
      51             :   //   because entries containing single-occurrence function names are quickly
      52             :   //   overwritten, and their copies released.  In addition, empty function
      53             :   //   names are common, so we use nullptr to represent them compactly.
      54             : 
      55             :   StringTable mLibraryStrings;
      56             : 
      57             :   struct Entry
      58             :   {
      59             :     const void* mPc;
      60             :     char*       mFunction;  // owned by the Entry;  may be null
      61             :     const char* mLibrary;   // owned by mLibraryStrings;  never null
      62             :                             //   in a non-empty entry is in use
      63             :     ptrdiff_t   mLOffset;
      64             :     char*       mFileName;  // owned by the Entry; may be null
      65             :     uint32_t    mLineNo:31;
      66             :     uint32_t    mInUse:1;   // is the entry used?
      67             : 
      68           0 :     Entry()
      69             :       : mPc(0), mFunction(nullptr), mLibrary(nullptr), mLOffset(0),
      70           0 :         mFileName(nullptr), mLineNo(0), mInUse(0)
      71           0 :     {}
      72             : 
      73           0 :     ~Entry()
      74             :     {
      75             :       // We don't free mLibrary because it's externally owned.
      76           0 :       StringAlloc::free(mFunction);
      77           0 :       StringAlloc::free(mFileName);
      78           0 :     }
      79             : 
      80           0 :     void Replace(const void* aPc, const char* aFunction,
      81             :                  const char* aLibrary, ptrdiff_t aLOffset,
      82             :                  const char* aFileName, unsigned long aLineNo)
      83             :     {
      84           0 :       mPc = aPc;
      85             : 
      86             :       // Convert "" to nullptr.  Otherwise, make a copy of the name.
      87           0 :       StringAlloc::free(mFunction);
      88           0 :       mFunction = !aFunction[0] ? nullptr : StringAlloc::copy(aFunction);
      89           0 :       StringAlloc::free(mFileName);
      90           0 :       mFileName = !aFileName[0] ? nullptr : StringAlloc::copy(aFileName);
      91             : 
      92           0 :       mLibrary = aLibrary;
      93           0 :       mLOffset = aLOffset;
      94           0 :       mLineNo = aLineNo;
      95             : 
      96           0 :       mInUse = 1;
      97           0 :     }
      98             : 
      99             :     size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     100             :     {
     101             :       // Don't measure mLibrary because it's externally owned.
     102             :       size_t n = 0;
     103             :       n += aMallocSizeOf(mFunction);
     104             :       n += aMallocSizeOf(mFileName);
     105             :       return n;
     106             :     }
     107             :   };
     108             : 
     109             :   // A direct-mapped cache.  When doing dmd::Analyze() just after starting
     110             :   // desktop Firefox (which is similar to analyzing after a longer-running
     111             :   // session, thanks to the limit on how many records we print), a cache with
     112             :   // 2^24 entries (which approximates an infinite-entry cache) has a ~91% hit
     113             :   // rate.  A cache with 2^12 entries has a ~83% hit rate, and takes up ~85 KiB
     114             :   // (on 32-bit platforms) or ~150 KiB (on 64-bit platforms).
     115             :   static const size_t kNumEntries = 1 << 12;
     116             :   static const size_t kMask = kNumEntries - 1;
     117             :   Entry mEntries[kNumEntries];
     118             : 
     119             :   size_t mNumCacheHits;
     120             :   size_t mNumCacheMisses;
     121             : 
     122             : public:
     123           0 :   CodeAddressService()
     124           0 :     : mEntries(), mNumCacheHits(0), mNumCacheMisses(0)
     125             :   {
     126           0 :   }
     127             : 
     128           0 :   void GetLocation(uint32_t aFrameNumber, const void* aPc, char* aBuf,
     129             :                    size_t aBufLen)
     130             :   {
     131           0 :     MOZ_ASSERT(DescribeCodeAddressLock::IsLocked());
     132             : 
     133           0 :     uint32_t index = HashGeneric(aPc) & kMask;
     134           0 :     MOZ_ASSERT(index < kNumEntries);
     135           0 :     Entry& entry = mEntries[index];
     136             : 
     137           0 :     if (!entry.mInUse || entry.mPc != aPc) {
     138           0 :       mNumCacheMisses++;
     139             : 
     140             :       // MozDescribeCodeAddress can (on Linux) acquire a lock inside
     141             :       // the shared library loader.  Another thread might call malloc
     142             :       // while holding that lock (when loading a shared library).  So
     143             :       // we have to exit the lock around this call.  For details, see
     144             :       // https://bugzilla.mozilla.org/show_bug.cgi?id=363334#c3
     145             :       MozCodeAddressDetails details;
     146             :       {
     147           0 :         DescribeCodeAddressLock::Unlock();
     148           0 :         (void)MozDescribeCodeAddress(const_cast<void*>(aPc), &details);
     149           0 :         DescribeCodeAddressLock::Lock();
     150             :       }
     151             : 
     152           0 :       const char* library = mLibraryStrings.Intern(details.library);
     153           0 :       entry.Replace(aPc, details.function, library, details.loffset,
     154           0 :                     details.filename, details.lineno);
     155             : 
     156             :     } else {
     157           0 :       mNumCacheHits++;
     158             :     }
     159             : 
     160           0 :     MOZ_ASSERT(entry.mPc == aPc);
     161             : 
     162           0 :     MozFormatCodeAddress(aBuf, aBufLen, aFrameNumber, entry.mPc,
     163           0 :                          entry.mFunction, entry.mLibrary, entry.mLOffset,
     164           0 :                          entry.mFileName, entry.mLineNo);
     165           0 :   }
     166             : 
     167             :   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     168             :   {
     169             :     size_t n = aMallocSizeOf(this);
     170             :     for (uint32_t i = 0; i < kNumEntries; i++) {
     171             :       n += mEntries[i].SizeOfExcludingThis(aMallocSizeOf);
     172             :     }
     173             : 
     174             :     n += mLibraryStrings.SizeOfExcludingThis(aMallocSizeOf);
     175             : 
     176             :     return n;
     177             :   }
     178             : 
     179             :   size_t CacheCapacity() const { return kNumEntries; }
     180             : 
     181             :   size_t CacheCount() const
     182             :   {
     183             :     size_t n = 0;
     184             :     for (size_t i = 0; i < kNumEntries; i++) {
     185             :       if (mEntries[i].mInUse) {
     186             :         n++;
     187             :       }
     188             :     }
     189             :     return n;
     190             :   }
     191             : 
     192             :   size_t NumCacheHits()   const { return mNumCacheHits; }
     193             :   size_t NumCacheMisses() const { return mNumCacheMisses; }
     194             : };
     195             : 
     196             : } // namespace mozilla
     197             : 
     198             : #endif // CodeAddressService_h__

Generated by: LCOV version 1.13