Bug 822148 (part 2) - DMD: Treat twice-reported blocks more like other blocks. r=jlebar.

--HG--
extra : rebase_source : 345123de945a3c26ec6ca88a599b45efddc4209e
This commit is contained in:
Nicholas Nethercote 2012-12-17 19:40:07 -08:00
parent 0d26120cb5
commit d1985a03e0
4 changed files with 400 additions and 375 deletions

View File

@ -772,8 +772,7 @@ StackTrace::Print(const Writer& aWriter, LocationService* aLocService) const
}
for (uint32_t i = 0; i < mLength; i++) {
void* pc = mPcs[i];
aLocService->WriteLocation(aWriter, pc);
aLocService->WriteLocation(aWriter, Pc(i));
}
}
@ -815,50 +814,88 @@ StackTrace::Get(Thread* aT)
// Heap blocks
//---------------------------------------------------------------------------
// This class combines a 2-byte-aligned pointer (i.e. one whose bottom bit
// is zero) with a 1-bit tag.
//
// |T| is the pointer type, e.g. |int*|, not the pointed-to type. This makes
// is easier to have const pointers, e.g. |TaggedPtr<const int*>|.
template <typename T>
class TaggedPtr
{
union
{
T mPtr;
uintptr_t mUint;
};
static const uintptr_t kTagMask = uintptr_t(0x1);
static const uintptr_t kPtrMask = ~kTagMask;
static bool IsTwoByteAligned(T aPtr)
{
return (uintptr_t(aPtr) & kTagMask) == 0;
}
public:
TaggedPtr()
: mPtr(nullptr)
{}
TaggedPtr(T aPtr, bool aBool)
: mPtr(aPtr)
{
MOZ_ASSERT(IsTwoByteAligned(aPtr));
uintptr_t tag = uintptr_t(aBool);
MOZ_ASSERT(tag <= kTagMask);
mUint |= (tag & kTagMask);
}
void Set(T aPtr, bool aBool)
{
MOZ_ASSERT(IsTwoByteAligned(aPtr));
mPtr = aPtr;
uintptr_t tag = uintptr_t(aBool);
MOZ_ASSERT(tag <= kTagMask);
mUint |= (tag & kTagMask);
}
T Ptr() const { return reinterpret_cast<T>(mUint & kPtrMask); }
bool Tag() const { return bool(mUint & kTagMask); }
};
// A live heap block.
class LiveBlock
{
const void* mPtr;
const size_t mReqSize; // size requested
// This assumes that we'll never request an allocation of 2 GiB or more on
// 32-bit platforms.
static const size_t kReqBits = sizeof(size_t) * 8 - 1; // 31 or 63
const size_t mReqSize:kReqBits; // size requested
const size_t mSampled:1; // was this block sampled? (if so, slop == 0)
// Ptr: |mAllocStackTrace| - stack trace where this block was allocated.
// Tag bit 0: |mSampled| - was this block sampled? (if so, slop == 0).
TaggedPtr<const StackTrace* const>
mAllocStackTrace_mSampled;
public:
const StackTrace* const mAllocStackTrace; // never null
// Live blocks can be reported in two ways.
// - The most common is via a memory reporter traversal -- the block is
// reported when the reporter runs, causing DMD to mark it as reported,
// and DMD must clear the marking once it has finished its analysis.
// - Less common are ones that are reported immediately on allocation. DMD
// must *not* clear the markings of these blocks once it has finished its
// analysis. The |mReportedOnAlloc| field is set for such blocks.
// This array has two elements because we record at most two reports of a
// block.
// - Ptr: |mReportStackTrace| - stack trace where this block was reported.
// nullptr if not reported.
// - Tag bit 0: |mReportedOnAlloc| - was the block reported immediately on
// allocation? If so, DMD must not clear the report at the end of Dump().
// Only relevant if |mReportStackTrace| is non-nullptr.
//
// |mPtr| is used as the key in LiveBlockTable, so it's ok for these fields
// |mPtr| is used as the key in LiveBlockTable, so it's ok for this member
// to be |mutable|.
private:
mutable const StackTrace* mReportStackTrace; // nullptr if unreported
mutable bool mReportedOnAlloc; // true if block was reported
// immediately after alloc
mutable TaggedPtr<const StackTrace*> mReportStackTrace_mReportedOnAlloc[2];
public:
LiveBlock(const void* aPtr, size_t aReqSize,
const StackTrace* aAllocStackTrace, bool aSampled)
: mPtr(aPtr),
mReqSize(aReqSize),
mSampled(aSampled),
mAllocStackTrace(aAllocStackTrace),
mReportStackTrace(nullptr),
mReportedOnAlloc(false)
{
if (mReqSize != aReqSize)
{
MOZ_CRASH(); // overflowed mReqSize
}
MOZ_ASSERT(mAllocStackTrace);
mAllocStackTrace_mSampled(aAllocStackTrace, aSampled),
mReportStackTrace_mReportedOnAlloc() // all fields get zeroed
{
MOZ_ASSERT(aAllocStackTrace);
}
size_t ReqSize() const { return mReqSize; }
@ -866,24 +903,78 @@ public:
// Sampled blocks always have zero slop.
size_t SlopSize() const
{
return mSampled ? 0 : MallocSizeOf(mPtr) - mReqSize;
return IsSampled() ? 0 : MallocSizeOf(mPtr) - mReqSize;
}
size_t UsableSize() const
{
return mSampled ? mReqSize : MallocSizeOf(mPtr);
return IsSampled() ? mReqSize : MallocSizeOf(mPtr);
}
bool IsSampled() const { return mSampled; }
bool IsSampled() const
{
return mAllocStackTrace_mSampled.Tag();
}
bool IsReported() const { return !!mReportStackTrace; }
const StackTrace* AllocStackTrace() const
{
return mAllocStackTrace_mSampled.Ptr();
}
const StackTrace* ReportStackTrace() const { return mReportStackTrace; }
const StackTrace* ReportStackTrace1() const {
return mReportStackTrace_mReportedOnAlloc[0].Ptr();
}
const StackTrace* ReportStackTrace2() const {
return mReportStackTrace_mReportedOnAlloc[1].Ptr();
}
bool ReportedOnAlloc1() const {
return mReportStackTrace_mReportedOnAlloc[0].Tag();
}
bool ReportedOnAlloc2() const {
return mReportStackTrace_mReportedOnAlloc[1].Tag();
}
uint32_t NumReports() const {
if (ReportStackTrace2()) {
MOZ_ASSERT(ReportStackTrace1());
return 2;
}
if (ReportStackTrace1()) {
return 1;
}
return 0;
}
// This is |const| thanks to the |mutable| fields above.
void Report(Thread* aT, bool aReportedOnAlloc) const;
void Report(Thread* aT, bool aReportedOnAlloc) const
{
// We don't bother recording reports after the 2nd one.
uint32_t numReports = NumReports();
if (numReports < 2) {
mReportStackTrace_mReportedOnAlloc[numReports].Set(StackTrace::Get(aT),
aReportedOnAlloc);
}
}
void UnreportIfNotReportedOnAlloc() const;
void UnreportIfNotReportedOnAlloc() const
{
if (!ReportedOnAlloc1() && !ReportedOnAlloc2()) {
mReportStackTrace_mReportedOnAlloc[0].Set(nullptr, 0);
mReportStackTrace_mReportedOnAlloc[1].Set(nullptr, 0);
} else if (!ReportedOnAlloc1() && ReportedOnAlloc2()) {
// Shift the 2nd report down to the 1st one.
mReportStackTrace_mReportedOnAlloc[0] =
mReportStackTrace_mReportedOnAlloc[1];
mReportStackTrace_mReportedOnAlloc[1].Set(nullptr, 0);
} else if (ReportedOnAlloc1() && !ReportedOnAlloc2()) {
mReportStackTrace_mReportedOnAlloc[1].Set(nullptr, 0);
}
}
// Hash policy.
@ -1102,81 +1193,38 @@ namespace mozilla {
namespace dmd {
//---------------------------------------------------------------------------
// Live and double-report block groups
// Block groups
//---------------------------------------------------------------------------
class LiveBlockKey
class BlockGroupKey
{
public:
const StackTrace* const mAllocStackTrace; // never null
protected:
const StackTrace* const mReportStackTrace; // nullptr if unreported
const StackTrace* const mReportStackTrace1; // nullptr if unreported
const StackTrace* const mReportStackTrace2; // nullptr if not 2x-reported
public:
LiveBlockKey(const LiveBlock& aB)
: mAllocStackTrace(aB.mAllocStackTrace),
mReportStackTrace(aB.ReportStackTrace())
BlockGroupKey(const LiveBlock& aB)
: mAllocStackTrace(aB.AllocStackTrace()),
mReportStackTrace1(aB.ReportStackTrace1()),
mReportStackTrace2(aB.ReportStackTrace2())
{
MOZ_ASSERT(mAllocStackTrace);
}
bool IsReported() const
{
return !!mReportStackTrace;
}
// Hash policy.
typedef LiveBlockKey Lookup;
typedef BlockGroupKey Lookup;
static uint32_t hash(const LiveBlockKey& aKey)
{
return mozilla::HashGeneric(aKey.mAllocStackTrace,
aKey.mReportStackTrace);
}
static bool match(const LiveBlockKey& aA, const LiveBlockKey& aB)
{
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
aA.mReportStackTrace == aB.mReportStackTrace;
}
};
class DoubleReportBlockKey
{
public:
const StackTrace* const mAllocStackTrace; // never null
protected:
// When double-reports occur we record (and later print) the stack trace
// of *both* the reporting locations.
const StackTrace* const mReportStackTrace1; // never null
const StackTrace* const mReportStackTrace2; // never null
public:
DoubleReportBlockKey(const StackTrace* aAllocStackTrace,
const StackTrace* aReportStackTrace1,
const StackTrace* aReportStackTrace2)
: mAllocStackTrace(aAllocStackTrace),
mReportStackTrace1(aReportStackTrace1),
mReportStackTrace2(aReportStackTrace2)
{
MOZ_ASSERT(mAllocStackTrace && mReportStackTrace1 && mReportStackTrace2);
}
// Hash policy.
typedef DoubleReportBlockKey Lookup;
static uint32_t hash(const DoubleReportBlockKey& aKey)
static uint32_t hash(const BlockGroupKey& aKey)
{
return mozilla::HashGeneric(aKey.mAllocStackTrace,
aKey.mReportStackTrace1,
aKey.mReportStackTrace2);
}
static bool match(const DoubleReportBlockKey& aA,
const DoubleReportBlockKey& aB)
static bool match(const BlockGroupKey& aA, const BlockGroupKey& aB)
{
return aA.mAllocStackTrace == aB.mAllocStackTrace &&
aA.mReportStackTrace1 == aB.mReportStackTrace1 &&
@ -1221,11 +1269,15 @@ public:
static int Cmp(const GroupSize& aA, const GroupSize& aB)
{
// Primary sort: put bigger usable sizes before smaller usable sizes.
// Primary sort: put bigger usable sizes first.
if (aA.Usable() > aB.Usable()) return -1;
if (aA.Usable() < aB.Usable()) return 1;
// Secondary sort: put non-sampled groups before sampled groups.
// Secondary sort: put bigger requested sizes first.
if (aA.Req() > aB.Req()) return -1;
if (aA.Req() < aB.Req()) return 1;
// Tertiary sort: put non-sampled groups before sampled groups.
if (!aA.mSampled && aB.mSampled) return -1;
if ( aA.mSampled && !aB.mSampled) return 1;
@ -1233,18 +1285,20 @@ public:
}
};
class BlockGroup
// A group of one or more heap blocks with a common BlockGroupKey.
class BlockGroup : public BlockGroupKey
{
protected:
// {Live,DoubleReport}BlockKey serve as the key in
// {Live,DoubleReport}BlockGroupTable. Thes two fields constitute the value,
// so it's ok for them to be |mutable|.
friend class FrameGroup; // FrameGroups are created from BlockGroups
// The BlockGroupKey base class serves as the key in BlockGroupTables. These
// two fields constitute the value, so it's ok for them to be |mutable|.
mutable uint32_t mNumBlocks; // number of blocks with this LiveBlockKey
mutable GroupSize mGroupSize; // combined size of those blocks
public:
BlockGroup()
: mNumBlocks(0),
explicit BlockGroup(const BlockGroupKey& aKey)
: BlockGroupKey(aKey),
mNumBlocks(0),
mGroupSize()
{}
@ -1258,20 +1312,6 @@ public:
}
static const char* const kName; // for PrintSortedGroups
};
const char* const BlockGroup::kName = "block";
// A group of one or more live heap blocks with a common LiveBlockKey.
class LiveBlockGroup : public LiveBlockKey, public BlockGroup
{
friend class FrameGroup; // FrameGroups are created from LiveBlockGroups
public:
explicit LiveBlockGroup(const LiveBlockKey& aKey)
: LiveBlockKey(aKey),
BlockGroup()
{}
void Print(const Writer& aWriter, LocationService* aLocService,
uint32_t aM, uint32_t aN, const char* aStr, const char* astr,
@ -1280,24 +1320,25 @@ public:
static int QsortCmp(const void* aA, const void* aB)
{
const LiveBlockGroup* const a =
*static_cast<const LiveBlockGroup* const*>(aA);
const LiveBlockGroup* const b =
*static_cast<const LiveBlockGroup* const*>(aB);
const BlockGroup* const a =
*static_cast<const BlockGroup* const*>(aA);
const BlockGroup* const b =
*static_cast<const BlockGroup* const*>(aB);
return GroupSize::Cmp(a->mGroupSize, b->mGroupSize);
}
};
typedef js::HashSet<LiveBlockGroup, LiveBlockGroup, InfallibleAllocPolicy>
LiveBlockGroupTable;
const char* const BlockGroup::kName = "block";
typedef js::HashSet<BlockGroup, BlockGroup, InfallibleAllocPolicy>
BlockGroupTable;
void
LiveBlockGroup::Print(const Writer& aWriter, LocationService* aLocService,
uint32_t aM, uint32_t aN,
const char* aStr, const char* astr,
size_t aCategoryUsableSize, size_t aCumulativeUsableSize,
size_t aTotalUsableSize) const
BlockGroup::Print(const Writer& aWriter, LocationService* aLocService,
uint32_t aM, uint32_t aN, const char* aStr, const char* astr,
size_t aCategoryUsableSize, size_t aCumulativeUsableSize,
size_t aTotalUsableSize) const
{
bool showTilde = mGroupSize.IsSampled();
@ -1323,74 +1364,14 @@ LiveBlockGroup::Print(const Writer& aWriter, LocationService* aLocService,
W(" Allocated at\n");
mAllocStackTrace->Print(aWriter, aLocService);
if (IsReported()) {
if (mReportStackTrace1) {
W("\n Reported at\n");
mReportStackTrace->Print(aWriter, aLocService);
mReportStackTrace1->Print(aWriter, aLocService);
}
W("\n");
}
// A group of one or more double-reported heap blocks with a common
// DoubleReportBlockKey.
class DoubleReportBlockGroup : public DoubleReportBlockKey, public BlockGroup
{
public:
explicit DoubleReportBlockGroup(const DoubleReportBlockKey& aKey)
: DoubleReportBlockKey(aKey),
BlockGroup()
{}
void Print(const Writer& aWriter, LocationService* aLocService,
uint32_t aM, uint32_t aN, const char* aStr, const char* astr,
size_t aCategoryUsableSize, size_t aCumulativeUsableSize,
size_t aTotalUsableSize) const;
static int QsortCmp(const void* aA, const void* aB)
{
const DoubleReportBlockGroup* const a =
*static_cast<const DoubleReportBlockGroup* const*>(aA);
const DoubleReportBlockGroup* const b =
*static_cast<const DoubleReportBlockGroup* const*>(aB);
return GroupSize::Cmp(a->mGroupSize, b->mGroupSize);
if (mReportStackTrace2) {
W("\n Reported again at\n");
mReportStackTrace2->Print(aWriter, aLocService);
}
};
typedef js::HashSet<DoubleReportBlockGroup, DoubleReportBlockGroup,
InfallibleAllocPolicy> DoubleReportBlockGroupTable;
DoubleReportBlockGroupTable* gDoubleReportBlockGroupTable = nullptr;
void
DoubleReportBlockGroup::Print(const Writer& aWriter,
LocationService* aLocService,
uint32_t aM, uint32_t aN,
const char* aStr, const char* astr,
size_t aCategoryUsableSize,
size_t aCumulativeUsableSize,
size_t aTotalUsableSize) const
{
bool showTilde = mGroupSize.IsSampled();
W("%s: %s block%s in block group %s of %s\n",
aStr,
Show(mNumBlocks, gBuf1, kBufLen, showTilde), Plural(mNumBlocks),
Show(aM, gBuf2, kBufLen),
Show(aN, gBuf3, kBufLen));
W(" %s bytes (%s requested / %s slop)\n",
Show(mGroupSize.Usable(), gBuf1, kBufLen, showTilde),
Show(mGroupSize.Req(), gBuf2, kBufLen, showTilde),
Show(mGroupSize.Slop(), gBuf3, kBufLen, showTilde));
W(" Allocated at\n");
mAllocStackTrace->Print(aWriter, aLocService);
W("\n Previously reported at\n");
mReportStackTrace1->Print(aWriter, aLocService);
W("\n Now reported at\n");
mReportStackTrace2->Print(aWriter, aLocService);
W("\n");
}
@ -1421,7 +1402,7 @@ public:
const GroupSize& GetGroupSize() const { return mGroupSize; }
// This is |const| thanks to the |mutable| fields above.
void Add(const LiveBlockGroup& aBg) const
void Add(const BlockGroup& aBg) const
{
mNumBlocks += aBg.mNumBlocks;
mNumBlockGroups++;
@ -1696,10 +1677,6 @@ Init(const malloc_table_t* aMallocTable)
gLiveBlockTable = InfallibleAllocPolicy::new_<LiveBlockTable>();
gLiveBlockTable->init(8192);
gDoubleReportBlockGroupTable =
InfallibleAllocPolicy::new_<DoubleReportBlockGroupTable>();
gDoubleReportBlockGroupTable->init(0);
if (gMode == Test) {
// OpenTestOrStressFile() can allocate. So do this before setting
// gIsDMDRunning so those allocations don't show up in our results. Once
@ -1732,36 +1709,8 @@ Init(const malloc_table_t* aMallocTable)
// DMD reporting and unreporting
//---------------------------------------------------------------------------
void
LiveBlock::Report(Thread* aT, bool aOnAlloc) const
{
if (IsReported()) {
DoubleReportBlockKey key(mAllocStackTrace, mReportStackTrace,
StackTrace::Get(aT));
DoubleReportBlockGroupTable::AddPtr p =
gDoubleReportBlockGroupTable->lookupForAdd(key);
if (!p) {
DoubleReportBlockGroup bg(key);
(void)gDoubleReportBlockGroupTable->add(p, bg);
}
p->Add(*this);
} else {
mReportStackTrace = StackTrace::Get(aT);
mReportedOnAlloc = aOnAlloc;
}
}
void
LiveBlock::UnreportIfNotReportedOnAlloc() const
{
if (!mReportedOnAlloc) {
mReportStackTrace = nullptr;
}
}
static void
ReportHelper(const void* aPtr, bool aOnAlloc)
ReportHelper(const void* aPtr, bool aReportedOnAlloc)
{
if (!gIsDMDRunning || !aPtr) {
return;
@ -1773,7 +1722,7 @@ ReportHelper(const void* aPtr, bool aOnAlloc)
AutoLockState lock;
if (LiveBlockTable::Ptr p = gLiveBlockTable->lookup(aPtr)) {
p->Report(t, aOnAlloc);
p->Report(t, aReportedOnAlloc);
} else {
// We have no record of the block. Do nothing. Either:
// - We're sampling and we skipped this block. This is likely.
@ -1798,7 +1747,7 @@ ReportOnAlloc(const void* aPtr)
// DMD output
//---------------------------------------------------------------------------
// This works for LiveBlockGroups, DoubleReportBlockGroups and FrameGroups.
// This works for BlockGroups and FrameGroups.
template <class TGroup>
static void
PrintSortedGroups(const Writer& aWriter, LocationService* aLocService,
@ -1856,11 +1805,11 @@ static void
PrintSortedBlockAndFrameGroups(const Writer& aWriter,
LocationService* aLocService,
const char* aStr, const char* astr,
const LiveBlockGroupTable& aLiveBlockGroupTable,
const BlockGroupTable& aBlockGroupTable,
size_t aCategoryUsableSize,
size_t aTotalUsableSize)
{
PrintSortedGroups(aWriter, aLocService, aStr, astr, aLiveBlockGroupTable,
PrintSortedGroups(aWriter, aLocService, aStr, astr, aBlockGroupTable,
aCategoryUsableSize, aTotalUsableSize);
// Frame groups are totally dependent on vagaries of stack traces, so we
@ -1871,10 +1820,10 @@ PrintSortedBlockAndFrameGroups(const Writer& aWriter,
FrameGroupTable frameGroupTable;
(void)frameGroupTable.init(2048);
for (LiveBlockGroupTable::Range r = aLiveBlockGroupTable.all();
for (BlockGroupTable::Range r = aBlockGroupTable.all();
!r.empty();
r.popFront()) {
const LiveBlockGroup& bg = r.front();
const BlockGroup& bg = r.front();
const StackTrace* st = bg.mAllocStackTrace;
// A single PC can appear multiple times in a stack trace. We ignore
@ -1925,9 +1874,6 @@ SizeOf(Sizes* aSizes)
gStackTraceTable->sizeOfIncludingThis(MallocSizeOf);
aSizes->mLiveBlockTable = gLiveBlockTable->sizeOfIncludingThis(MallocSizeOf);
aSizes->mDoubleReportTable =
gDoubleReportBlockGroupTable->sizeOfIncludingThis(MallocSizeOf);
}
static void
@ -1940,10 +1886,6 @@ ClearGlobalState()
r.popFront()) {
r.front().UnreportIfNotReportedOnAlloc();
}
// Clear errors.
gDoubleReportBlockGroupTable->finish();
(void)gDoubleReportBlockGroupTable->init();
}
MOZ_EXPORT void
@ -1962,15 +1904,19 @@ Dump(Writer aWriter)
static int dumpCount = 1;
StatusMsg("Dump %d {\n", dumpCount++);
StatusMsg(" gathering live block groups...\n");
StatusMsg(" gathering block groups...\n");
LiveBlockGroupTable unreportedLiveBlockGroupTable;
(void)unreportedLiveBlockGroupTable.init(1024);
BlockGroupTable unreportedBlockGroupTable;
(void)unreportedBlockGroupTable.init(1024);
size_t unreportedUsableSize = 0;
LiveBlockGroupTable reportedLiveBlockGroupTable;
(void)reportedLiveBlockGroupTable.init(1024);
size_t reportedUsableSize = 0;
BlockGroupTable onceReportedBlockGroupTable;
(void)onceReportedBlockGroupTable.init(1024);
size_t onceReportedUsableSize = 0;
BlockGroupTable twiceReportedBlockGroupTable;
(void)twiceReportedBlockGroupTable.init(0);
size_t twiceReportedUsableSize = 0;
bool anyBlocksSampled = false;
@ -1979,23 +1925,31 @@ Dump(Writer aWriter)
r.popFront()) {
const LiveBlock& b = r.front();
size_t& size = !b.IsReported() ? unreportedUsableSize : reportedUsableSize;
size += b.UsableSize();
LiveBlockGroupTable& table = !b.IsReported()
? unreportedLiveBlockGroupTable
: reportedLiveBlockGroupTable;
LiveBlockKey liveKey(b);
LiveBlockGroupTable::AddPtr p = table.lookupForAdd(liveKey);
BlockGroupTable* table;
uint32_t numReports = b.NumReports();
if (numReports == 0) {
unreportedUsableSize += b.UsableSize();
table = &unreportedBlockGroupTable;
} else if (numReports == 1) {
onceReportedUsableSize += b.UsableSize();
table = &onceReportedBlockGroupTable;
} else {
MOZ_ASSERT(numReports == 2);
twiceReportedUsableSize += b.UsableSize();
table = &twiceReportedBlockGroupTable;
}
BlockGroupKey key(b);
BlockGroupTable::AddPtr p = table->lookupForAdd(key);
if (!p) {
LiveBlockGroup bg(b);
(void)table.add(p, bg);
BlockGroup bg(b);
(void)table->add(p, bg);
}
p->Add(b);
anyBlocksSampled = anyBlocksSampled || b.IsSampled();
}
size_t totalUsableSize = unreportedUsableSize + reportedUsableSize;
size_t totalUsableSize =
unreportedUsableSize + onceReportedUsableSize + twiceReportedUsableSize;
WriteTitle("Invocation\n");
W("$DMD = '%s'\n", gDMDEnvVar);
@ -2004,29 +1958,33 @@ Dump(Writer aWriter)
// Allocate this on the heap instead of the stack because it's fairly large.
LocationService* locService = InfallibleAllocPolicy::new_<LocationService>();
PrintSortedGroups(aWriter, locService, "Double-reported", "double-reported",
*gDoubleReportBlockGroupTable, kNoSize, kNoSize);
PrintSortedGroups(aWriter, locService, "Twice-reported", "twice-reported",
twiceReportedBlockGroupTable, twiceReportedUsableSize,
totalUsableSize);
PrintSortedBlockAndFrameGroups(aWriter, locService,
"Unreported", "unreported",
unreportedLiveBlockGroupTable,
unreportedBlockGroupTable,
unreportedUsableSize, totalUsableSize);
PrintSortedBlockAndFrameGroups(aWriter, locService,
"Reported", "reported",
reportedLiveBlockGroupTable,
reportedUsableSize, totalUsableSize);
"Once-reported", "once-reported",
onceReportedBlockGroupTable,
onceReportedUsableSize, totalUsableSize);
bool showTilde = anyBlocksSampled;
WriteTitle("Summary\n");
W("Total: %s bytes\n",
W("Total: %10s bytes\n",
Show(totalUsableSize, gBuf1, kBufLen, showTilde));
W("Reported: %s bytes (%5.2f%%)\n",
Show(reportedUsableSize, gBuf1, kBufLen, showTilde),
Percent(reportedUsableSize, totalUsableSize));
W("Unreported: %s bytes (%5.2f%%)\n",
W("Unreported: %10s bytes (%5.2f%%)\n",
Show(unreportedUsableSize, gBuf1, kBufLen, showTilde),
Percent(unreportedUsableSize, totalUsableSize));
W("Once-reported: %10s bytes (%5.2f%%)\n",
Show(onceReportedUsableSize, gBuf1, kBufLen, showTilde),
Percent(onceReportedUsableSize, totalUsableSize));
W("Twice-reported: %10s bytes (%5.2f%%)\n",
Show(twiceReportedUsableSize, gBuf1, kBufLen, showTilde),
Percent(twiceReportedUsableSize, totalUsableSize));
W("\n");
@ -2039,43 +1997,43 @@ Dump(Writer aWriter)
W("Data structures that persist after Dump() ends:\n");
W(" Stack traces: %10s bytes\n",
W(" Stack traces: %10s bytes\n",
Show(sizes.mStackTraces, gBuf1, kBufLen));
W(" Stack trace table: %10s bytes (%s entries, %s used)\n",
W(" Stack trace table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mStackTraceTable, gBuf1, kBufLen),
Show(gStackTraceTable->capacity(), gBuf2, kBufLen),
Show(gStackTraceTable->count(), gBuf3, kBufLen));
W(" Live block table: %10s bytes (%s entries, %s used)\n",
W(" Live block table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mLiveBlockTable, gBuf1, kBufLen),
Show(gLiveBlockTable->capacity(), gBuf2, kBufLen),
Show(gLiveBlockTable->count(), gBuf3, kBufLen));
W("\nData structures that are partly cleared after Dump() ends:\n");
W(" Double-report table: %10s bytes (%s entries, %s used)\n",
Show(sizes.mDoubleReportTable, gBuf1, kBufLen),
Show(gDoubleReportBlockGroupTable->capacity(), gBuf2, kBufLen),
Show(gDoubleReportBlockGroupTable->count(), gBuf3, kBufLen));
W("\nData structures that are destroyed after Dump() ends:\n");
size_t unreportedSize =
unreportedLiveBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Unreported table: %10s bytes (%s entries, %s used)\n",
Show(unreportedSize, gBuf1, kBufLen),
Show(unreportedLiveBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(unreportedLiveBlockGroupTable.count(), gBuf3, kBufLen));
unreportedBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Unreported table: %10s bytes (%s entries, %s used)\n",
Show(unreportedSize, gBuf1, kBufLen),
Show(unreportedBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(unreportedBlockGroupTable.count(), gBuf3, kBufLen));
size_t reportedSize =
reportedLiveBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Reported table: %10s bytes (%s entries, %s used)\n",
Show(reportedSize, gBuf1, kBufLen),
Show(reportedLiveBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(reportedLiveBlockGroupTable.count(), gBuf3, kBufLen));
size_t onceReportedSize =
onceReportedBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Once-reported table: %10s bytes (%s entries, %s used)\n",
Show(onceReportedSize, gBuf1, kBufLen),
Show(onceReportedBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(onceReportedBlockGroupTable.count(), gBuf3, kBufLen));
W(" Location service: %10s bytes\n",
size_t twiceReportedSize =
twiceReportedBlockGroupTable.sizeOfIncludingThis(MallocSizeOf);
W(" Twice-reported table: %10s bytes (%s entries, %s used)\n",
Show(twiceReportedSize, gBuf1, kBufLen),
Show(twiceReportedBlockGroupTable.capacity(), gBuf2, kBufLen),
Show(twiceReportedBlockGroupTable.count(), gBuf3, kBufLen));
W(" Location service: %10s bytes\n",
Show(locService->SizeOfIncludingThis(), gBuf1, kBufLen));
W("\nCounts:\n");
@ -2158,7 +2116,7 @@ RunTestMode(FILE* fp)
// Min-sized block.
// 1st Dump: reported.
// 2nd Dump: re-reported, twice; double-report warning.
// 2nd Dump: thrice-reported.
char* a2 = (char*) malloc(0);
Report(a2);
@ -2175,7 +2133,7 @@ RunTestMode(FILE* fp)
ReportOnAlloc(b2);
free(b2);
// 1st Dump: reported, plus 3 double-report warnings.
// 1st Dump: reported 4 times.
// 2nd Dump: freed, irrelevant.
char* c = (char*) calloc(10, 3);
Report(c);
@ -2223,6 +2181,24 @@ RunTestMode(FILE* fp)
foo();
foo();
// 1st Dump: twice-reported.
// 2nd Dump: twice-reported.
char* g1 = (char*) malloc(77);
ReportOnAlloc(g1);
ReportOnAlloc(g1);
// 1st Dump: twice-reported.
// 2nd Dump: once-reported.
char* g2 = (char*) malloc(78);
Report(g2);
ReportOnAlloc(g2);
// 1st Dump: twice-reported.
// 2nd Dump: once-reported.
char* g3 = (char*) malloc(79);
ReportOnAlloc(g3);
Report(g3);
// All the odd-ball ones.
// 1st Dump: all unreported.
// 2nd Dump: all freed, irrelevant.

View File

@ -55,7 +55,6 @@ struct Sizes
size_t mStackTraces;
size_t mStackTraceTable;
size_t mLiveBlockTable;
size_t mDoubleReportTable;
Sizes() { Clear(); }
void Clear() { memset(this, 0, sizeof(Sizes)); }

View File

@ -6,7 +6,7 @@ $DMD = '--mode=test'
Sample-below size = 1
------------------------------------------------------------------
Double-reported blocks
Twice-reported blocks
------------------------------------------------------------------
(none)
@ -18,7 +18,7 @@ Unreported blocks
(none)
------------------------------------------------------------------
Reported blocks
Once-reported blocks
------------------------------------------------------------------
(none)
@ -27,9 +27,10 @@ Reported blocks
Summary
------------------------------------------------------------------
Total: 0 bytes
Reported: 0 bytes ( 0.00%)
Unreported: 0 bytes ( 0.00%)
Total: 0 bytes
Unreported: 0 bytes ( 0.00%)
Once-reported: 0 bytes ( 0.00%)
Twice-reported: 0 bytes ( 0.00%)
------------------------------------------------------------------
Invocation
@ -39,18 +40,55 @@ $DMD = '--mode=test'
Sample-below size = 1
------------------------------------------------------------------
Double-reported blocks
Twice-reported blocks
------------------------------------------------------------------
Double-reported: 3 blocks in block group 1 of 1
96 bytes (90 requested / 6 slop)
Twice-reported: 1 block in block group 1 of 4
80 bytes (79 requested / 1 slop)
0.53% of the heap (0.53% cumulative); 29.41% of twice-reported (29.41% cumulative)
Allocated at
(stack omitted due to test mode)
Previously reported at
Reported at
(stack omitted due to test mode)
Now reported at
Reported again at
(stack omitted due to test mode)
Twice-reported: 1 block in block group 2 of 4
80 bytes (78 requested / 2 slop)
0.53% of the heap (1.05% cumulative); 29.41% of twice-reported (58.82% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported again at
(stack omitted due to test mode)
Twice-reported: 1 block in block group 3 of 4
80 bytes (77 requested / 3 slop)
0.53% of the heap (1.58% cumulative); 29.41% of twice-reported (88.24% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported again at
(stack omitted due to test mode)
Twice-reported: 1 block in block group 4 of 4
32 bytes (30 requested / 2 slop)
0.21% of the heap (1.79% cumulative); 11.76% of twice-reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported again at
(stack omitted due to test mode)
------------------------------------------------------------------
@ -59,134 +97,125 @@ Unreported blocks
Unreported: 1 block in block group 1 of 4
4,096 bytes (1 requested / 4,095 slop)
27.44% of the heap (27.44% cumulative); 76.88% of unreported (76.88% cumulative)
27.00% of the heap (27.00% cumulative); 76.88% of unreported (76.88% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 9 blocks in block group 2 of 4
1,008 bytes (900 requested / 108 slop)
6.75% of the heap (34.19% cumulative); 18.92% of unreported (95.80% cumulative)
6.65% of the heap (33.65% cumulative); 18.92% of unreported (95.80% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 2 blocks in block group 3 of 4
112 bytes (112 requested / 0 slop)
0.75% of the heap (34.94% cumulative); 2.10% of unreported (97.90% cumulative)
0.74% of the heap (34.39% cumulative); 2.10% of unreported (97.90% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 2 blocks in block group 4 of 4
112 bytes (112 requested / 0 slop)
0.75% of the heap (35.69% cumulative); 2.10% of unreported (100.00% cumulative)
0.74% of the heap (35.13% cumulative); 2.10% of unreported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
Once-reported blocks
------------------------------------------------------------------
Reported: 1 block in block group 1 of 12
Once-reported: 1 block in block group 1 of 11
8,192 bytes (4,097 requested / 4,095 slop)
54.88% of the heap (54.88% cumulative); 85.33% of reported (85.33% cumulative)
54.01% of the heap (54.01% cumulative); 85.62% of once-reported (85.62% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 2 of 12
Once-reported: 1 block in block group 2 of 11
512 bytes (512 requested / 0 slop)
3.43% of the heap (58.31% cumulative); 5.33% of reported (90.67% cumulative)
3.38% of the heap (57.38% cumulative); 5.35% of once-reported (90.97% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 2 blocks in block group 3 of 12
Once-reported: 2 blocks in block group 3 of 11
240 bytes (240 requested / 0 slop)
1.61% of the heap (59.91% cumulative); 2.50% of reported (93.17% cumulative)
1.58% of the heap (58.97% cumulative); 2.51% of once-reported (93.48% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 2 blocks in block group 4 of 12
Once-reported: 2 blocks in block group 4 of 11
240 bytes (240 requested / 0 slop)
1.61% of the heap (61.52% cumulative); 2.50% of reported (95.67% cumulative)
1.58% of the heap (60.55% cumulative); 2.51% of once-reported (95.99% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 5 of 12
Once-reported: 1 block in block group 5 of 11
96 bytes (96 requested / 0 slop)
0.64% of the heap (62.17% cumulative); 1.00% of reported (96.67% cumulative)
0.63% of the heap (61.18% cumulative); 1.00% of once-reported (96.99% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 6 of 12
Once-reported: 1 block in block group 6 of 11
96 bytes (96 requested / 0 slop)
0.64% of the heap (62.81% cumulative); 1.00% of reported (97.67% cumulative)
0.63% of the heap (61.81% cumulative); 1.00% of once-reported (97.99% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 7 of 12
Once-reported: 1 block in block group 7 of 11
80 bytes (80 requested / 0 slop)
0.54% of the heap (63.34% cumulative); 0.83% of reported (98.50% cumulative)
0.53% of the heap (62.34% cumulative); 0.84% of once-reported (98.83% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 8 of 12
Once-reported: 1 block in block group 8 of 11
80 bytes (80 requested / 0 slop)
0.54% of the heap (63.88% cumulative); 0.83% of reported (99.33% cumulative)
0.53% of the heap (62.87% cumulative); 0.84% of once-reported (99.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 9 of 12
32 bytes (30 requested / 2 slop)
0.21% of the heap (64.09% cumulative); 0.33% of reported (99.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 10 of 12
Once-reported: 1 block in block group 9 of 11
16 bytes (10 requested / 6 slop)
0.11% of the heap (64.20% cumulative); 0.17% of reported (99.83% cumulative)
0.11% of the heap (62.97% cumulative); 0.17% of once-reported (99.83% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 11 of 12
Once-reported: 1 block in block group 10 of 11
8 bytes (0 requested / 8 slop)
0.05% of the heap (64.26% cumulative); 0.08% of reported (99.92% cumulative)
0.05% of the heap (63.03% cumulative); 0.08% of once-reported (99.92% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 12 of 12
Once-reported: 1 block in block group 11 of 11
8 bytes (0 requested / 8 slop)
0.05% of the heap (64.31% cumulative); 0.08% of reported (100.00% cumulative)
0.05% of the heap (63.08% cumulative); 0.08% of once-reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
@ -197,9 +226,10 @@ Reported: 1 block in block group 12 of 12
Summary
------------------------------------------------------------------
Total: 14,928 bytes
Reported: 9,600 bytes (64.31%)
Unreported: 5,328 bytes (35.69%)
Total: 15,168 bytes
Unreported: 5,328 bytes (35.13%)
Once-reported: 9,568 bytes (63.08%)
Twice-reported: 272 bytes ( 1.79%)
------------------------------------------------------------------
Invocation
@ -209,18 +239,31 @@ $DMD = '--mode=test'
Sample-below size = 1
------------------------------------------------------------------
Double-reported blocks
Twice-reported blocks
------------------------------------------------------------------
Double-reported: 1 block in block group 1 of 1
8 bytes (0 requested / 8 slop)
Twice-reported: 1 block in block group 1 of 2
80 bytes (77 requested / 3 slop)
2.82% of the heap (2.82% cumulative); 90.91% of twice-reported (90.91% cumulative)
Allocated at
(stack omitted due to test mode)
Previously reported at
Reported at
(stack omitted due to test mode)
Now reported at
Reported again at
(stack omitted due to test mode)
Twice-reported: 1 block in block group 2 of 2
8 bytes (0 requested / 8 slop)
0.28% of the heap (3.10% cumulative); 9.09% of twice-reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported again at
(stack omitted due to test mode)
------------------------------------------------------------------
@ -229,47 +272,56 @@ Unreported blocks
Unreported: 9 blocks in block group 1 of 3
1,008 bytes (900 requested / 108 slop)
38.77% of the heap (38.77% cumulative); 48.84% of unreported (48.84% cumulative)
35.49% of the heap (35.49% cumulative); 48.84% of unreported (48.84% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 6 blocks in block group 2 of 3
528 bytes (528 requested / 0 slop)
20.31% of the heap (59.08% cumulative); 25.58% of unreported (74.42% cumulative)
18.59% of the heap (54.08% cumulative); 25.58% of unreported (74.42% cumulative)
Allocated at
(stack omitted due to test mode)
Unreported: 6 blocks in block group 3 of 3
528 bytes (528 requested / 0 slop)
20.31% of the heap (79.38% cumulative); 25.58% of unreported (100.00% cumulative)
18.59% of the heap (72.68% cumulative); 25.58% of unreported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
Once-reported blocks
------------------------------------------------------------------
Reported: 1 block in block group 1 of 3
Once-reported: 1 block in block group 1 of 4
512 bytes (512 requested / 0 slop)
19.69% of the heap (19.69% cumulative); 95.52% of reported (95.52% cumulative)
18.03% of the heap (18.03% cumulative); 74.42% of once-reported (74.42% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 2 of 3
Once-reported: 1 block in block group 2 of 4
80 bytes (79 requested / 1 slop)
2.82% of the heap (20.85% cumulative); 11.63% of once-reported (86.05% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Once-reported: 1 block in block group 3 of 4
80 bytes (78 requested / 2 slop)
2.82% of the heap (23.66% cumulative); 11.63% of once-reported (97.67% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Once-reported: 1 block in block group 4 of 4
16 bytes (10 requested / 6 slop)
0.62% of the heap (20.31% cumulative); 2.99% of reported (98.51% cumulative)
Allocated at
(stack omitted due to test mode)
Reported at
(stack omitted due to test mode)
Reported: 1 block in block group 3 of 3
8 bytes (0 requested / 8 slop)
0.31% of the heap (20.62% cumulative); 1.49% of reported (100.00% cumulative)
0.56% of the heap (24.23% cumulative); 2.33% of once-reported (100.00% cumulative)
Allocated at
(stack omitted due to test mode)
@ -280,9 +332,10 @@ Reported: 1 block in block group 3 of 3
Summary
------------------------------------------------------------------
Total: 2,600 bytes
Reported: 536 bytes (20.62%)
Unreported: 2,064 bytes (79.38%)
Total: 2,840 bytes
Unreported: 2,064 bytes (72.68%)
Once-reported: 688 bytes (24.23%)
Twice-reported: 88 bytes ( 3.10%)
------------------------------------------------------------------
Invocation
@ -292,7 +345,7 @@ $DMD = '--mode=test'
Sample-below size = 128
------------------------------------------------------------------
Double-reported blocks
Twice-reported blocks
------------------------------------------------------------------
(none)
@ -344,7 +397,7 @@ Unreported: ~1 block in block group 7 of 7
(stack omitted due to test mode)
------------------------------------------------------------------
Reported blocks
Once-reported blocks
------------------------------------------------------------------
(none)
@ -353,7 +406,8 @@ Reported blocks
Summary
------------------------------------------------------------------
Total: ~1,424 bytes
Reported: ~0 bytes ( 0.00%)
Unreported: ~1,424 bytes (100.00%)
Total: ~1,424 bytes
Unreported: ~1,424 bytes (100.00%)
Once-reported: ~0 bytes ( 0.00%)
Twice-reported: ~0 bytes ( 0.00%)

View File

@ -608,10 +608,6 @@ public:
sizes.mLiveBlockTable,
"Memory used by DMD's live block table.");
REPORT("explicit/dmd/double-report-table",
sizes.mDoubleReportTable,
"Memory used by DMD's double-report table.");
#undef REPORT
return NS_OK;